Merge "Clarify expired deadline meaning for periodic jobs."
diff --git a/Android.bp b/Android.bp
index 72e519c..07e6b36 100644
--- a/Android.bp
+++ b/Android.bp
@@ -585,7 +585,6 @@
"--hide RequiresPermission " +
"--hide SdkConstant " +
"--hide Todo " +
- "--hide Typo " +
"--hide UnavailableSymbol " +
"--manifest $(location :frameworks-base-core-AndroidManifest.xml) "
diff --git a/apct-tests/perftests/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
index 11d1106..58cf58b 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidTest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -58,8 +58,8 @@
<option name="instrumentation-arg" key="report" value="true" />
<option name="instrumentation-arg" key="arguments" value="-g" />
<option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
- <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger" />
- <option name="instrumentation-arg" key="symbols_to_report" value=""commit;android::SurfaceFlinger::commit(;composite;android::SurfaceFlinger::composite("" />
+ <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger,android.perftests.surfaceflinger" />
+ <option name="instrumentation-arg" key="symbols_to_report" value=""commit;android::SurfaceFlinger::commit(;composite;android::SurfaceFlinger::composite(;outbound;android::SurfaceComposerClient::Transaction::apply(;inbound;android::BnTransactionCompletedListener::onTransact(""/>
<!-- should match profiling-iterations -->
<option name="instrumentation-arg" key="test_iterations" value="525" />
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index d5315da..8494326 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -52,9 +52,9 @@
import android.content.res.Resources;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RevocableFileDescriptor;
import android.os.UserHandle;
-import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArrayMap;
@@ -298,8 +298,8 @@
}
}
- final boolean canCallerAccessBlobsAcrossUsers = checkCallerCanAccessBlobsAcrossUsers(
- callingPackage, callingUserId);
+ final boolean canCallerAccessBlobsAcrossUsers =
+ checkCallerCanAccessBlobsAcrossUsers(callingUid);
if (!canCallerAccessBlobsAcrossUsers) {
return false;
}
@@ -325,12 +325,11 @@
return false;
}
- private static boolean checkCallerCanAccessBlobsAcrossUsers(
- String callingPackage, int callingUserId) {
+ private boolean checkCallerCanAccessBlobsAcrossUsers(int callingUid) {
final long token = Binder.clearCallingIdentity();
try {
- return PermissionManager.checkPackageNamePermission(ACCESS_BLOBS_ACROSS_USERS,
- callingPackage, callingUserId) == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkPermission(ACCESS_BLOBS_ACROSS_USERS,
+ Process.INVALID_PID, callingUid) == PackageManager.PERMISSION_GRANTED;
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index fbee604..76d1935 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -374,6 +374,8 @@
private boolean mBatterySaverEnabled;
@GuardedBy("this")
private boolean mIsOffBody;
+ @GuardedBy("this")
+ private boolean mForceBodyState;
private Sensor mOffBodySensor;
/** Time in the elapsed realtime timebase when this listener last received a motion event. */
@@ -850,17 +852,27 @@
return;
}
synchronized (DeviceIdleController.this) {
- mIsOffBody = (event.values[0] == 0);
- // Get into quick doze faster when the device is off body instead of taking
- // traditional multi-stage approach.
- updateQuickDozeFlagLocked();
- if (!mIsOffBody && !mBatterySaverEnabled) {
- mActiveReason = ACTIVE_REASON_ONBODY;
- becomeActiveLocked("onbody", Process.myUid());
+ final boolean isOffBody = (event.values[0] == 0);
+ if (!mForceBodyState && mIsOffBody != isOffBody) {
+ // Only consider the sensor value change when mForceBodyState is false, which
+ // is used to enforce the mIsOffBody to be set by the adb shell command.
+ mIsOffBody = isOffBody;
+ onOffBodyChangedLocked();
}
}
}
+ @GuardedBy("DeviceIdleController.this")
+ public void onOffBodyChangedLocked() {
+ // Get into quick doze faster when the device is off body instead of taking
+ // traditional multi-stage approach.
+ updateQuickDozeFlagLocked();
+ if (!mIsOffBody && !mBatterySaverEnabled) {
+ mActiveReason = ACTIVE_REASON_ONBODY;
+ becomeActiveLocked("onbody", Process.myUid());
+ }
+ }
+
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
@@ -4468,8 +4480,10 @@
pw.println(" force-inactive");
pw.println(" Force to be inactive, ready to freely step idle states.");
pw.println(" unforce");
- pw.println(" Resume normal functioning after force-idle or force-inactive.");
- pw.println(" get [light|deep|force|screen|charging|network]");
+ pw.println(
+ " Resume normal functioning after force-idle or force-inactive or "
+ + "force-offbody or force-onbody.");
+ pw.println(" get [light|deep|force|screen|charging|network|offbody|forcebodystate]");
pw.println(" Retrieve the current given state.");
pw.println(" disable [light|deep|all]");
pw.println(" Completely disable device idle mode.");
@@ -4503,6 +4517,14 @@
+ "and any [-d] is ignored");
pw.println(" motion");
pw.println(" Simulate a motion event to bring the device out of deep doze");
+ pw.println(" force-offbody");
+ pw.println(
+ " Simulate a low latency body sensor detecting a device is offbody. "
+ + "mForceBodyState will be set to true to ignore body sensor reading.");
+ pw.println(" force-onbody");
+ pw.println(
+ " Simulate a low latency body sensor detecting a device is onbody. "
+ + "mForceBodyState will be set to true to ignore body sensor reading.");
}
class Shell extends ShellCommand {
@@ -4634,6 +4656,8 @@
pw.print(lightStateToString(mLightState));
pw.print(", deep state: ");
pw.println(stateToString(mState));
+ mForceBodyState = false;
+ pw.println("mForceBodyState: " + mForceBodyState);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -4654,6 +4678,8 @@
case "screen": pw.println(mScreenOn); break;
case "charging": pw.println(mCharging); break;
case "network": pw.println(mNetworkConnected); break;
+ case "offbody": pw.println(mIsOffBody); break;
+ case "forcebodystate": pw.println(mForceBodyState); break;
default: pw.println("Unknown get option: " + arg); break;
}
} finally {
@@ -4950,6 +4976,36 @@
Binder.restoreCallingIdentity(token);
}
}
+ } else if ("force-offbody".equals(cmd)) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+ synchronized (DeviceIdleController.this) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mForceBodyState = true;
+ pw.println("mForceBodyState: " + mForceBodyState);
+ mIsOffBody = true;
+ pw.println("mIsOffBody: " + mIsOffBody);
+ mLowLatencyOffBodyListener.onOffBodyChangedLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } else if ("force-onbody".equals(cmd)) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+ synchronized (DeviceIdleController.this) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mForceBodyState = true;
+ pw.println("mForceBodyState: " + mForceBodyState);
+ mIsOffBody = false;
+ pw.println("mIsOffBody: " + mIsOffBody);
+ mLowLatencyOffBodyListener.onOffBodyChangedLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
} else {
return shell.handleDefaultCommands(cmd);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 4d646de..a720baf 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -21,6 +21,7 @@
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
+import static com.android.server.alarm.AlarmManagerService.PRIORITY_NORMAL;
import static com.android.server.alarm.AlarmManagerService.clampPositive;
import android.app.AlarmManager;
@@ -128,8 +129,9 @@
/** The ultimate delivery time to be used for this alarm */
private long mWhenElapsed;
private long mMaxWhenElapsed;
- public int mExactAllowReason;
- public AlarmManagerService.PriorityClass priorityClass;
+ public int exactAllowReason;
+ @AlarmManagerService.DispatchPriority
+ public int priorityClass;
/** Broadcast options to use when delivering this alarm */
public Bundle mIdleOptions;
public boolean mUsingReserveQuota;
@@ -158,10 +160,11 @@
this.uid = uid;
packageName = pkgName;
mIdleOptions = idleOptions;
- mExactAllowReason = exactAllowReason;
+ this.exactAllowReason = exactAllowReason;
sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid;
mUsingReserveQuota = false;
+ priorityClass = PRIORITY_NORMAL;
}
public static String makeTag(PendingIntent pi, String tag, int type) {
@@ -333,9 +336,9 @@
}
ipw.print(" window=");
TimeUtils.formatDuration(windowLength, ipw);
- if (mExactAllowReason != EXACT_ALLOW_REASON_NOT_APPLICABLE) {
+ if (exactAllowReason != EXACT_ALLOW_REASON_NOT_APPLICABLE) {
ipw.print(" exactAllowReason=");
- ipw.print(exactReasonToString(mExactAllowReason));
+ ipw.print(exactReasonToString(exactAllowReason));
}
ipw.print(" repeatInterval=");
ipw.print(repeatInterval);
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 9299295..2557c6a 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -70,7 +70,9 @@
import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.EnforcePermission;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManagerInternal;
@@ -175,6 +177,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -182,7 +186,6 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashMap;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
@@ -730,9 +733,6 @@
@VisibleForTesting
static final String KEY_MAX_DEVICE_IDLE_FUZZ = "max_device_idle_fuzz";
@VisibleForTesting
- static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
- "kill_on_schedule_exact_alarm_revoked";
- @VisibleForTesting
static final String KEY_TEMPORARY_QUOTA_BUMP = "temporary_quota_bump";
@VisibleForTesting
static final String KEY_CACHED_LISTENER_REMOVAL_DELAY = "cached_listener_removal_delay";
@@ -775,8 +775,6 @@
private static final long DEFAULT_MIN_DEVICE_IDLE_FUZZ = 2 * 60_000;
private static final long DEFAULT_MAX_DEVICE_IDLE_FUZZ = 15 * 60_000;
- private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true;
-
private static final int DEFAULT_TEMPORARY_QUOTA_BUMP = 0;
private static final boolean DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = true;
@@ -855,13 +853,6 @@
*/
public long MAX_DEVICE_IDLE_FUZZ = DEFAULT_MAX_DEVICE_IDLE_FUZZ;
- /**
- * Whether or not to kill app when the permission
- * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} is revoked.
- */
- public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
- DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
-
public int USE_TARE_POLICY = EconomyManager.DEFAULT_ENABLE_POLICY_ALARM
? EconomyManager.DEFAULT_ENABLE_TARE_MODE : EconomyManager.ENABLED_MODE_OFF;
@@ -913,6 +904,7 @@
economyManagerInternal.getEnabledMode(AlarmManagerEconomicPolicy.POLICY_ALARM));
}
+ @SuppressLint("MissingPermission")
public void updateAllowWhileIdleWhitelistDurationLocked() {
if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
@@ -1055,11 +1047,6 @@
deviceIdleFuzzBoundariesUpdated = true;
}
break;
- case KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED:
- KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = properties.getBoolean(
- KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
- DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
- break;
case KEY_TEMPORARY_QUOTA_BUMP:
TEMPORARY_QUOTA_BUMP = properties.getInt(KEY_TEMPORARY_QUOTA_BUMP,
DEFAULT_TEMPORARY_QUOTA_BUMP);
@@ -1303,10 +1290,6 @@
TimeUtils.formatDuration(MAX_DEVICE_IDLE_FUZZ, pw);
pw.println();
- pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
- KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
- pw.println();
-
pw.print(Settings.Global.ENABLE_TARE,
EconomyManager.enabledModeToString(USE_TARE_POLICY));
pw.println();
@@ -1342,87 +1325,91 @@
Constants mConstants;
- // Alarm delivery ordering bookkeeping
- static final int PRIO_TICK = 0;
- static final int PRIO_WAKEUP = 1;
- static final int PRIO_NORMAL = 2;
+ /** Dispatch priority to use for system alarms. */
+ static final int PRIORITY_SYSTEM = 0;
+ /** Dispatch priority to use for a package that has any wakeup alarm in the pending batch. */
+ static final int PRIORITY_WAKEUP = 1;
+ /** The default dispatch priority to use when no special conditions apply. */
+ static final int PRIORITY_NORMAL = 2;
- final class PriorityClass {
- int seq;
- int priority;
+ /**
+ * Priority to assign to alarms in an outgoing batch. Higher priority alarms are considered more
+ * urgent than lower priority ones (smaller value is higher priority). Priorities are assigned
+ * per package, so all alarms in one package will share the same priority in an outgoing batch -
+ * which should be the highest (minimum) priority computed over all its alarms.
+ * This is done to ensure that alarms in the same package preserve their relative ordering.
+ */
+ @IntDef(prefix = "PRIORITY_", value = {
+ PRIORITY_SYSTEM,
+ PRIORITY_WAKEUP,
+ PRIORITY_NORMAL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DispatchPriority {}
- PriorityClass() {
- seq = mCurrentSeq - 1;
- priority = PRIO_NORMAL;
+ final Comparator<Alarm> mAlarmDispatchComparator = (lhs, rhs) -> {
+
+ // Alarm to exit device_idle should go out first.
+ final boolean idleUntil1 = (lhs.flags & FLAG_IDLE_UNTIL) != 0;
+ final boolean idleUntil2 = (rhs.flags & FLAG_IDLE_UNTIL) != 0;
+ if (idleUntil1 != idleUntil2) {
+ return idleUntil1 ? -1 : 1;
}
- }
- final HashMap<String, PriorityClass> mPriorities = new HashMap<>();
- int mCurrentSeq = 0;
-
- final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
- @Override
- public int compare(Alarm lhs, Alarm rhs) {
-
- // Alarm to exit device_idle should go out first.
- final boolean lhsIdleUntil = (lhs.flags & FLAG_IDLE_UNTIL) != 0;
- final boolean rhsIdleUntil = (rhs.flags & FLAG_IDLE_UNTIL) != 0;
- if (lhsIdleUntil != rhsIdleUntil) {
- return lhsIdleUntil ? -1 : 1;
- }
-
- // Then, priority class trumps everything. TICK < WAKEUP < NORMAL
- if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
- return -1;
- } else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
- return 1;
- }
-
- // within each class, sort by requested delivery time
- if (lhs.getRequestedElapsed() < rhs.getRequestedElapsed()) {
- return -1;
- } else if (lhs.getRequestedElapsed() > rhs.getRequestedElapsed()) {
- return 1;
- }
-
- return 0;
+ // Then, priority class trumps everything. SYSTEM < WAKEUP < NORMAL
+ if (lhs.priorityClass < rhs.priorityClass) {
+ return -1;
+ } else if (lhs.priorityClass > rhs.priorityClass) {
+ return 1;
}
+
+ // Within all system alarms, pulling time_tick to the front, as it is time-sensitive.
+ final boolean timeTick1 = (lhs.listener == mTimeTickTrigger);
+ final boolean timeTick2 = (rhs.listener == mTimeTickTrigger);
+ if (timeTick1 != timeTick2) {
+ return timeTick1 ? -1 : 1;
+ }
+
+ // Within each class, sort by requested delivery time
+ if (lhs.getRequestedElapsed() < rhs.getRequestedElapsed()) {
+ return -1;
+ } else if (lhs.getRequestedElapsed() > rhs.getRequestedElapsed()) {
+ return 1;
+ }
+
+ return 0;
};
+ /**
+ * Assigns a {@link DispatchPriority} to each alarm that will be used to order alarms in an
+ * outgoing batch.
+ *
+ * @param alarms The batch of alarms about to be sent.
+ */
void calculateDeliveryPriorities(ArrayList<Alarm> alarms) {
final int N = alarms.size();
+
+ // Batches are expected to be small (generally N < 10). So an additional iteration to
+ // collect a small set of UserPackage objects should be unnoticeable.
+ final ArraySet<UserPackage> wakeupPackages = new ArraySet<>(4);
for (int i = 0; i < N; i++) {
- Alarm a = alarms.get(i);
-
- final int alarmPrio;
- if (a.listener == mTimeTickTrigger) {
- alarmPrio = PRIO_TICK;
- } else if (a.wakeup) {
- alarmPrio = PRIO_WAKEUP;
- } else {
- alarmPrio = PRIO_NORMAL;
+ final Alarm a = alarms.get(i);
+ if (a.wakeup) {
+ wakeupPackages.add(
+ UserPackage.of(UserHandle.getUserId(a.creatorUid), a.sourcePackage));
}
+ }
- PriorityClass packagePrio = a.priorityClass;
- String alarmPackage = a.sourcePackage;
- if (packagePrio == null) packagePrio = mPriorities.get(alarmPackage);
- if (packagePrio == null) {
- packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
- mPriorities.put(alarmPackage, packagePrio);
- }
- a.priorityClass = packagePrio;
+ for (int i = 0; i < N; i++) {
+ final Alarm a = alarms.get(i);
- if (packagePrio.seq != mCurrentSeq) {
- // first alarm we've seen in the current delivery generation from this package
- packagePrio.priority = alarmPrio;
- packagePrio.seq = mCurrentSeq;
+ if (a.creatorUid == Process.SYSTEM_UID && "android".equals(a.sourcePackage)) {
+ a.priorityClass = PRIORITY_SYSTEM;
+ } else if (wakeupPackages.contains(
+ UserPackage.of(UserHandle.getUserId(a.creatorUid), a.sourcePackage))) {
+ a.priorityClass = PRIORITY_WAKEUP;
} else {
- // Multiple alarms from this package being delivered in this generation;
- // bump the package's delivery class if it's warranted.
- // TICK < WAKEUP < NORMAL
- if (alarmPrio < packagePrio.priority) {
- packagePrio.priority = alarmPrio;
- }
+ a.priorityClass = PRIORITY_NORMAL;
}
}
}
@@ -1727,6 +1714,7 @@
final BroadcastStats mBroadcastStats;
final FilterStats mFilterStats;
final int mAlarmType;
+ final int mPriorityClass;
InFlight(AlarmManagerService service, Alarm alarm, long nowELAPSED) {
mPendingIntent = alarm.operation;
@@ -1747,6 +1735,7 @@
fs.lastTime = nowELAPSED;
mFilterStats = fs;
mAlarmType = alarm.type;
+ mPriorityClass = alarm.priorityClass;
}
boolean isBroadcast() {
@@ -1765,6 +1754,7 @@
+ ", broadcastStats=" + mBroadcastStats
+ ", filterStats=" + mFilterStats
+ ", alarmType=" + mAlarmType
+ + ", priorityClass=" + mPriorityClass
+ "}";
}
@@ -4080,7 +4070,7 @@
removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
}
- if (killUid && mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
+ if (killUid) {
PermissionManagerService.killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
"schedule_exact_alarm revoked");
}
@@ -4419,9 +4409,6 @@
}
}
- // This is a new alarm delivery set; bump the sequence number to indicate that
- // all apps' alarm delivery classes should be recalculated.
- mCurrentSeq++;
calculateDeliveryPriorities(triggerList);
Collections.sort(triggerList, mAlarmDispatchComparator);
@@ -5291,7 +5278,6 @@
// external-applications-unavailable case
removeLocked(pkg, REMOVE_REASON_UNDEFINED);
}
- mPriorities.remove(pkg);
for (int i = mBroadcastStats.size() - 1; i >= 0; i--) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
if (uidStats.remove(pkg) != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index eb1848d..90a6455a 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -112,7 +112,7 @@
(a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0,
a.alarmClock != null,
a.repeatInterval != 0,
- reasonToStatsReason(a.mExactAllowReason),
+ reasonToStatsReason(a.exactAllowReason),
AlarmManagerService.isRtc(a.type),
ActivityManager.processStateAmToProto(callerProcState));
}
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 05a43ad..4f9059f 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -502,9 +502,13 @@
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
- int in = data.readFileDescriptor();
- int out = data.readFileDescriptor();
- int err = data.readFileDescriptor();
+ unique_fd in, out, err;
+ if (status_t status = data.readUniqueFileDescriptor(&in); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&out); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&err); status != OK) return status;
+
int argc = data.readInt32();
Vector<String8> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
@@ -517,15 +521,15 @@
return BAD_VALUE;
}
- FILE* fin = fdopen(in, "r");
- FILE* fout = fdopen(out, "w");
- FILE* ferr = fdopen(err, "w");
+ FILE* fin = fdopen(in.release(), "r");
+ FILE* fout = fdopen(out.release(), "w");
+ FILE* ferr = fdopen(err.release(), "w");
if (fin == NULL || fout == NULL || ferr == NULL) {
resultReceiver->send(NO_MEMORY);
} else {
- err = command(fin, fout, ferr, args);
- resultReceiver->send(err);
+ status_t result = command(fin, fout, ferr, args);
+ resultReceiver->send(result);
}
if (fin != NULL) {
diff --git a/core/api/current.txt b/core/api/current.txt
index a2c1b1b..d0e32a7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9609,6 +9609,7 @@
method public int describeContents();
method public int getDeviceId();
method @Nullable public String getName();
+ method @Nullable public String getPersistentDeviceId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
}
@@ -14204,6 +14205,46 @@
ctor public SQLiteAccessPermException(String);
}
+ public interface SQLiteAuthorizer {
+ method public int onAuthorize(int, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+ field public static final int SQLITE_ACTION_ALTER_TABLE = 26; // 0x1a
+ field public static final int SQLITE_ACTION_ANALYZE = 28; // 0x1c
+ field public static final int SQLITE_ACTION_ATTACH = 24; // 0x18
+ field public static final int SQLITE_ACTION_CREATE_INDEX = 1; // 0x1
+ field public static final int SQLITE_ACTION_CREATE_TABLE = 2; // 0x2
+ field public static final int SQLITE_ACTION_CREATE_TEMP_INDEX = 3; // 0x3
+ field public static final int SQLITE_ACTION_CREATE_TEMP_TABLE = 4; // 0x4
+ field public static final int SQLITE_ACTION_CREATE_TEMP_TRIGGER = 5; // 0x5
+ field public static final int SQLITE_ACTION_CREATE_TEMP_VIEW = 6; // 0x6
+ field public static final int SQLITE_ACTION_CREATE_TRIGGER = 7; // 0x7
+ field public static final int SQLITE_ACTION_CREATE_VIEW = 8; // 0x8
+ field public static final int SQLITE_ACTION_CREATE_VTABLE = 29; // 0x1d
+ field public static final int SQLITE_ACTION_DELETE = 9; // 0x9
+ field public static final int SQLITE_ACTION_DETACH = 25; // 0x19
+ field public static final int SQLITE_ACTION_DROP_INDEX = 10; // 0xa
+ field public static final int SQLITE_ACTION_DROP_TABLE = 11; // 0xb
+ field public static final int SQLITE_ACTION_DROP_TEMP_INDEX = 12; // 0xc
+ field public static final int SQLITE_ACTION_DROP_TEMP_TABLE = 13; // 0xd
+ field public static final int SQLITE_ACTION_DROP_TEMP_TRIGGER = 14; // 0xe
+ field public static final int SQLITE_ACTION_DROP_TEMP_VIEW = 15; // 0xf
+ field public static final int SQLITE_ACTION_DROP_TRIGGER = 16; // 0x10
+ field public static final int SQLITE_ACTION_DROP_VIEW = 17; // 0x11
+ field public static final int SQLITE_ACTION_DROP_VTABLE = 30; // 0x1e
+ field public static final int SQLITE_ACTION_FUNCTION = 31; // 0x1f
+ field public static final int SQLITE_ACTION_INSERT = 18; // 0x12
+ field public static final int SQLITE_ACTION_PRAGMA = 19; // 0x13
+ field public static final int SQLITE_ACTION_READ = 20; // 0x14
+ field public static final int SQLITE_ACTION_RECURSIVE = 33; // 0x21
+ field public static final int SQLITE_ACTION_REINDEX = 27; // 0x1b
+ field public static final int SQLITE_ACTION_SAVEPOINT = 32; // 0x20
+ field public static final int SQLITE_ACTION_SELECT = 21; // 0x15
+ field public static final int SQLITE_ACTION_TRANSACTION = 22; // 0x16
+ field public static final int SQLITE_ACTION_UPDATE = 23; // 0x17
+ field public static final int SQLITE_AUTHORIZER_RESULT_DENY = 1; // 0x1
+ field public static final int SQLITE_AUTHORIZER_RESULT_IGNORE = 2; // 0x2
+ field public static final int SQLITE_AUTHORIZER_RESULT_OK = 0; // 0x0
+ }
+
public class SQLiteBindOrColumnIndexOutOfRangeException extends android.database.sqlite.SQLiteException {
ctor public SQLiteBindOrColumnIndexOutOfRangeException();
ctor public SQLiteBindOrColumnIndexOutOfRangeException(String);
@@ -14260,6 +14301,7 @@
method public void beginTransactionWithListenerNonExclusive(@Nullable android.database.sqlite.SQLiteTransactionListener);
method public void beginTransactionWithListenerReadOnly(@Nullable android.database.sqlite.SQLiteTransactionListener);
method public android.database.sqlite.SQLiteStatement compileStatement(String) throws android.database.SQLException;
+ method @NonNull public android.database.sqlite.SQLiteStatement compileStatement(@NonNull String, @NonNull android.database.sqlite.SQLiteAuthorizer) throws android.database.SQLException;
method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
method public int delete(String, String, String[]);
@@ -14270,6 +14312,7 @@
method public void execPerConnectionSQL(@NonNull String, @Nullable Object[]) throws android.database.SQLException;
method public void execSQL(String) throws android.database.SQLException;
method public void execSQL(String, Object[]) throws android.database.SQLException;
+ method public void execSQL(@NonNull String, @Nullable Object[], @NonNull android.database.sqlite.SQLiteAuthorizer) throws android.database.SQLException;
method public static String findEditTable(String);
method public java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttachedDbs();
method public long getMaximumSize();
@@ -14281,6 +14324,7 @@
method public long insert(String, String, android.content.ContentValues);
method public long insertOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
method public long insertWithOnConflict(String, String, android.content.ContentValues, int);
+ method public boolean isAuthorizerSupportEnabled();
method public boolean isDatabaseIntegrityOk();
method public boolean isDbLockedByCurrentThread();
method @Deprecated public boolean isDbLockedByOtherThreads();
@@ -14307,6 +14351,7 @@
method public android.database.Cursor rawQuery(String, String[], android.os.CancellationSignal);
method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String);
method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String, android.os.CancellationSignal);
+ method @NonNull public android.database.Cursor rawQueryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @NonNull String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal, @NonNull android.database.sqlite.SQLiteAuthorizer);
method public static int releaseMemory();
method public long replace(String, String, android.content.ContentValues);
method public long replaceOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
@@ -14323,6 +14368,7 @@
method public int update(String, android.content.ContentValues, String, String[]);
method public int updateWithOnConflict(String, android.content.ContentValues, String, String[], int);
method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal);
+ method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull android.database.sqlite.SQLiteAuthorizer);
method @Deprecated public boolean yieldIfContended();
method public boolean yieldIfContendedSafely();
method public boolean yieldIfContendedSafely(long);
@@ -14371,7 +14417,9 @@
ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams build();
+ method public boolean isAuthorizerSupportEnabled();
method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
+ method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setAuthorizerSupportEnabled(boolean);
method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(@Nullable android.database.DatabaseErrorHandler);
method @Deprecated @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(@IntRange(from=0) long);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7a86971e..928e41d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3200,6 +3200,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method public int getDeviceId();
+ method @Nullable public String getPersistentDeviceId();
method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensor> getVirtualSensorList();
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 529604d..255b45e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1303,6 +1303,7 @@
public final class SQLiteDirectCursorDriver implements android.database.sqlite.SQLiteCursorDriver {
ctor public SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal);
+ ctor public SQLiteDirectCursorDriver(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable android.database.sqlite.SQLiteAuthorizer, @NonNull String, @Nullable String, @Nullable android.os.CancellationSignal);
method public void cursorClosed();
method public void cursorDeactivated();
method public void cursorRequeried(android.database.Cursor);
@@ -1972,6 +1973,39 @@
method public android.media.PlaybackParams setAudioStretchMode(int);
}
+ public final class RingtoneSelection {
+ method @NonNull public static android.media.RingtoneSelection fromUri(@Nullable android.net.Uri, int);
+ method public int getSoundSource();
+ method @Nullable public android.net.Uri getSoundUri();
+ method public int getVibrationSource();
+ method @Nullable public android.net.Uri getVibrationUri();
+ method public static boolean isRingtoneSelectionUri(@Nullable android.net.Uri);
+ method @NonNull public android.net.Uri toUri();
+ field public static final String DEFAULT_SELECTION_URI_STRING = "content://media/ringtone";
+ field public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3; // 0x3
+ field public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1; // 0x1
+ field public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2; // 0x2
+ field public static final int SOUND_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int SOUND_SOURCE_OFF = 1; // 0x1
+ field public static final int SOUND_SOURCE_URI = 2; // 0x2
+ field public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3; // 0x3
+ field public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10; // 0xa
+ field public static final int VIBRATION_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11; // 0xb
+ field public static final int VIBRATION_SOURCE_OFF = 1; // 0x1
+ field public static final int VIBRATION_SOURCE_URI = 2; // 0x2
+ }
+
+ public static final class RingtoneSelection.Builder {
+ ctor public RingtoneSelection.Builder();
+ ctor public RingtoneSelection.Builder(@NonNull android.media.RingtoneSelection);
+ method @NonNull public android.media.RingtoneSelection build();
+ method @NonNull public android.media.RingtoneSelection.Builder setSoundSource(int);
+ method @NonNull public android.media.RingtoneSelection.Builder setSoundSource(@NonNull android.net.Uri);
+ method @NonNull public android.media.RingtoneSelection.Builder setVibrationSource(int);
+ method @NonNull public android.media.RingtoneSelection.Builder setVibrationSource(@NonNull android.net.Uri);
+ }
+
public static final class VolumeShaper.Configuration.Builder {
method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
}
@@ -3419,7 +3453,6 @@
}
public final class Choreographer {
- method public long getExpectedPresentationTimeNanos();
method public static long getFrameDelay();
method public long getFrameTimeNanos();
method public void postCallback(int, Runnable, Object);
@@ -4185,6 +4218,7 @@
public static class WindowInfosListenerForTest.WindowInfo {
field @NonNull public final android.graphics.Rect bounds;
+ field public final int displayId;
field public final boolean isTrustedOverlay;
field public final boolean isVisible;
field @NonNull public final String name;
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index d96a9d1..34f0964 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -39,7 +39,6 @@
import android.os.UserHandle;
import android.permission.IPermissionManager;
import android.util.Log;
-import android.util.Pair;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -52,7 +51,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.window.ScreenCapture;
import android.window.ScreenCapture.CaptureArgs;
-import android.window.ScreenCapture.ScreenCaptureListener;
+import android.window.ScreenCapture.ScreenshotHardwareBuffer;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import libcore.io.IoUtils;
@@ -235,12 +235,12 @@
final CaptureArgs captureArgs = new CaptureArgs.Builder<>()
.setSourceCrop(crop)
.build();
- Pair<ScreenCaptureListener, ScreenCapture.ScreenshotSync> syncScreenCapture =
+ SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
mWindowManager.captureDisplay(DEFAULT_DISPLAY, captureArgs,
- syncScreenCapture.first);
- final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
- syncScreenCapture.second.get();
+ syncScreenCapture);
+ final ScreenshotHardwareBuffer screenshotBuffer =
+ syncScreenCapture.getBuffer();
return screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
} catch (RemoteException re) {
re.rethrowAsRuntimeException();
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index b710644..5f5a7df 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -28,6 +28,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
+import android.os.Trace;
import android.util.Log;
import android.util.MathUtils;
import android.util.Size;
@@ -144,6 +145,7 @@
throw new IllegalArgumentException("Drawable cannot be null");
}
+ Trace.beginSection("WallpaperColors#fromDrawable");
Rect initialBounds = drawable.copyBounds();
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
@@ -165,6 +167,7 @@
bitmap.recycle();
drawable.setBounds(initialBounds);
+ Trace.endSection();
return colors;
}
@@ -195,7 +198,7 @@
public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap,
@FloatRange (from = 0f, to = 1f) float dimAmount) {
Objects.requireNonNull(bitmap, "Bitmap can't be null");
-
+ Trace.beginSection("WallpaperColors#fromBitmap");
final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
boolean shouldRecycle = false;
if (bitmapArea > MAX_WALLPAPER_EXTRACTION_AREA) {
@@ -247,6 +250,7 @@
bitmap.recycle();
}
+ Trace.endSection();
return new WallpaperColors(populationByColor, HINT_FROM_BITMAP | hints);
}
@@ -462,7 +466,7 @@
* Gets the most visually representative color of the wallpaper.
* "Visually representative" means easily noticeable in the image,
* probably happening at high frequency.
- *
+ *fromBitmap
* @return A color.
*/
public @NonNull Color getPrimaryColor() {
@@ -545,6 +549,7 @@
return 0;
}
+ Trace.beginSection("WallpaperColors#calculateDarkHints");
dimAmount = MathUtils.saturate(dimAmount);
int[] pixels = new int[source.getWidth() * source.getHeight()];
double totalLuminance = 0;
@@ -607,6 +612,7 @@
" maxD: " + maxDarkPixels + " numPixels: " + pixels.length);
}
+ Trace.endSection();
return hints;
}
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index ed53967..ffc4480 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -136,7 +136,7 @@
}
/**
- * Two instances of WifiSsidPolicy is considered equal if they have
+ * Two instances of WifiSsidPolicy are considered equal if they have
* the same WifiSsidPolicyType and the same set of WifiSsids
*/
@Override
diff --git a/core/java/android/app/smartspace/SmartspaceAction.java b/core/java/android/app/smartspace/SmartspaceAction.java
index f17b044..4475fc5 100644
--- a/core/java/android/app/smartspace/SmartspaceAction.java
+++ b/core/java/android/app/smartspace/SmartspaceAction.java
@@ -348,6 +348,10 @@
*/
@NonNull
public SmartspaceAction build() {
+ if (mIcon != null) {
+ mIcon.convertToAshmem();
+ }
+
return new SmartspaceAction(mId, mIcon, mTitle, mSubtitle, mContentDescription,
mPendingIntent, mIntent, mUserHandle, mExtras);
}
diff --git a/core/java/android/app/smartspace/uitemplatedata/Icon.java b/core/java/android/app/smartspace/uitemplatedata/Icon.java
index 6bdc926..b9d90bf 100644
--- a/core/java/android/app/smartspace/uitemplatedata/Icon.java
+++ b/core/java/android/app/smartspace/uitemplatedata/Icon.java
@@ -171,6 +171,7 @@
*/
@NonNull
public Icon build() {
+ mIcon.convertToAshmem();
return new Icon(mIcon, mContentDescription, mShouldTint);
}
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2e67225..4dea4a7 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -36,7 +36,6 @@
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.companion.utils.FeatureUtils;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -1227,11 +1226,6 @@
@Nullable
public IntentSender buildPermissionTransferUserConsentIntent(int associationId)
throws DeviceNotAssociatedException {
- if (!FeatureUtils.isPermSyncEnabled()) {
- throw new UnsupportedOperationException("Calling"
- + " buildPermissionTransferUserConsentIntent, but this API is disabled by the"
- + " system.");
- }
try {
PendingIntent pendingIntent = mService.buildPermissionTransferUserConsentIntent(
mContext.getOpPackageName(),
@@ -1264,10 +1258,6 @@
@Deprecated
@UserHandleAware
public void startSystemDataTransfer(int associationId) throws DeviceNotAssociatedException {
- if (!FeatureUtils.isPermSyncEnabled()) {
- throw new UnsupportedOperationException("Calling startSystemDataTransfer, but this API"
- + " is disabled by the system.");
- }
try {
mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(),
associationId, null);
@@ -1300,10 +1290,6 @@
@NonNull Executor executor,
@NonNull OutcomeReceiver<Void, CompanionException> result)
throws DeviceNotAssociatedException {
- if (!FeatureUtils.isPermSyncEnabled()) {
- throw new UnsupportedOperationException("Calling startSystemDataTransfer, but this API"
- + " is disabled by the system.");
- }
try {
mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(),
associationId, new SystemDataTransferCallbackProxy(executor, result));
diff --git a/core/java/android/companion/OWNERS b/core/java/android/companion/OWNERS
index 0348fe2..54d9c24 100644
--- a/core/java/android/companion/OWNERS
+++ b/core/java/android/companion/OWNERS
@@ -1,3 +1,5 @@
evanxinchen@google.com
guojing@google.com
-raphk@google.com
\ No newline at end of file
+jeremyns@google.com
+raphk@google.com
+yukl@google.com
\ No newline at end of file
diff --git a/core/java/android/companion/utils/FeatureUtils.java b/core/java/android/companion/utils/FeatureUtils.java
index 157eef8..a382e09 100644
--- a/core/java/android/companion/utils/FeatureUtils.java
+++ b/core/java/android/companion/utils/FeatureUtils.java
@@ -16,6 +16,7 @@
package android.companion.utils;
+import android.os.Binder;
import android.os.Build;
import android.provider.DeviceConfig;
@@ -31,8 +32,19 @@
private static final String PROPERTY_PERM_SYNC_ENABLED = "perm_sync_enabled";
public static boolean isPermSyncEnabled() {
- return Build.isDebuggable() || DeviceConfig.getBoolean(NAMESPACE_COMPANION,
- PROPERTY_PERM_SYNC_ENABLED, false);
+ // Permissions sync is always enabled in debuggable mode.
+ if (Build.isDebuggable()) {
+ return true;
+ }
+
+ // Clear app identity to read the device config for feature flag.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(NAMESPACE_COMPANION,
+ PROPERTY_PERM_SYNC_ENABLED, false);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
private FeatureUtils() {
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 9efdf28..4801d15 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -59,6 +59,11 @@
int getDeviceId();
/**
+ * Returns the persistent ID of this virtual device.
+ */
+ String getPersistentDeviceId();
+
+ /**
* Closes the virtual device and frees all associated resources.
*/
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index 4ee65e0..ceaf7e4 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -35,6 +35,7 @@
public final class VirtualDevice implements Parcelable {
private final int mId;
+ private final @Nullable String mPersistentId;
private final @Nullable String mName;
/**
@@ -43,28 +44,55 @@
*
* @hide
*/
- public VirtualDevice(int id, @Nullable String name) {
+ public VirtualDevice(int id, @Nullable String persistentId, @Nullable String name) {
if (id <= Context.DEVICE_ID_DEFAULT) {
- throw new IllegalArgumentException("VirtualDevice ID mist be greater than "
+ throw new IllegalArgumentException("VirtualDevice ID must be greater than "
+ Context.DEVICE_ID_DEFAULT);
}
mId = id;
+ mPersistentId = persistentId;
mName = name;
}
private VirtualDevice(@NonNull Parcel parcel) {
mId = parcel.readInt();
+ mPersistentId = parcel.readString8();
mName = parcel.readString8();
}
/**
* Returns the unique ID of the virtual device.
+ *
+ * <p>This identifier corresponds to {@link Context#getDeviceId()} and can be used to access
+ * device-specific system capabilities.
+ *
+ * <p class="note">This identifier is ephemeral and should not be used for persisting any data
+ * per device.
+ *
+ * @see Context#createDeviceContext
+ * @see #getPersistentDeviceId
*/
public int getDeviceId() {
return mId;
}
/**
+ * Returns the persistent identifier of this virtual device, if any.
+ *
+ * <p> If there is no stable identifier for this virtual device, then this returns {@code null}.
+
+ * <p>This identifier may correspond to a physical device. In that case it remains valid for as
+ * long as that physical device is associated with the host device and may be used to persist
+ * data per device.
+ *
+ * <p class="note">This identifier may not be unique across virtual devices, in case there are
+ * more than one virtual devices corresponding to the same physical device.
+ */
+ public @Nullable String getPersistentDeviceId() {
+ return mPersistentId;
+ }
+
+ /**
* Returns the name of the virtual device (optionally) provided during its creation.
*
* @see VirtualDeviceParams.Builder#setName(String)
@@ -81,6 +109,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mId);
+ dest.writeString8(mPersistentId);
dest.writeString8(mName);
}
@@ -94,12 +123,13 @@
}
VirtualDevice that = (VirtualDevice) o;
return mId == that.mId
+ && Objects.equals(mPersistentId, that.mPersistentId)
&& Objects.equals(mName, that.mName);
}
@Override
public int hashCode() {
- return Objects.hash(mId, mName);
+ return Objects.hash(mId, mPersistentId, mName);
}
@Override
@@ -107,6 +137,7 @@
public String toString() {
return "VirtualDevice("
+ " mId=" + mId
+ + " mPersistentId=" + mPersistentId
+ " mName=" + mName
+ ")";
}
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index 045e4c6..f68cfff 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -160,6 +160,14 @@
}
}
+ @Nullable String getPersistentDeviceId() {
+ try {
+ return mVirtualDevice.getPersistentDeviceId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@NonNull Context createContext() {
try {
return mContext.createDeviceContext(mVirtualDevice.getDeviceId());
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index fba896d..c10e898 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -102,6 +102,13 @@
public static final String EXTRA_VIRTUAL_DEVICE_ID =
"android.companion.virtual.extra.VIRTUAL_DEVICE_ID";
+ /**
+ * A representation of an invalid CDM association ID. Association IDs must be positive.
+ *
+ * @hide
+ */
+ public static final int ASSOCIATION_ID_INVALID = -1;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
@@ -367,6 +374,13 @@
}
/**
+ * Returns the persistent ID of this virtual device.
+ */
+ public @Nullable String getPersistentDeviceId() {
+ return mVirtualDeviceInternal.getPersistentDeviceId();
+ }
+
+ /**
* Returns a new context bound to this device.
*
* <p>This is a convenience method equivalent to calling
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c221d72..06635ee 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -481,7 +481,7 @@
* If binding from a top app and its target SDK version is at or above
* {@link android.os.Build.VERSION_CODES#R}, the app needs to
* explicitly use BIND_INCLUDE_CAPABILITIES flag to pass all capabilities to the service so the
- * other app can have while-use-use access such as location, camera, microphone from background.
+ * other app can have while-in-use access such as location, camera, microphone from background.
* If binding from a top app and its target SDK version is below
* {@link android.os.Build.VERSION_CODES#R}, BIND_INCLUDE_CAPABILITIES is implicit.
*/
@@ -678,7 +678,7 @@
* </p>
*
* <em>This flag is NOT compatible with {@link BindServiceFlags}. If you need to use
- * {@link BindServiceFlags}, you must use {@link #BIND_EXTERNAL_SERVICE_LONG} instead.
+ * {@link BindServiceFlags}, you must use {@link #BIND_EXTERNAL_SERVICE_LONG} instead.</em>
*/
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index fb41b89..225b3d3 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -445,7 +445,7 @@
@VisibleForTesting
public static class Builder extends GenericDocument.Builder<Builder> {
- private List<String> mFlags = new ArrayList<>(1);
+ private final List<String> mFlags = new ArrayList<>(1);
public Builder(String packageName, String id) {
super(/*namespace=*/ packageName, id, SCHEMA_TYPE);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 3487e0b..f0b99f1 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -67,7 +67,7 @@
* <application> tag.
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
- private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
+ private static final ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
@@ -1892,7 +1892,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Collator sCollator = Collator.getInstance();
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private PackageManager mPM;
+ private final PackageManager mPM;
}
public ApplicationInfo() {
diff --git a/core/java/android/content/pm/Attribution.java b/core/java/android/content/pm/Attribution.java
index 989a5b9..3649249 100644
--- a/core/java/android/content/pm/Attribution.java
+++ b/core/java/android/content/pm/Attribution.java
@@ -33,7 +33,7 @@
/**
* The tag of this attribution. From the <manifest> tag's "tag" attribute
*/
- private @NonNull String mTag;
+ private final @NonNull String mTag;
/**
* The resource ID of the label of the attribution From the <manifest> tag's "label"
@@ -43,7 +43,7 @@
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -146,10 +146,10 @@
};
@DataClass.Generated(
- time = 1608139558081L,
- codegenVersion = "1.0.22",
+ time = 1683311736586L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/Attribution.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String mTag\nprivate final @android.annotation.IdRes int mLabel\nclass Attribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mTag\nprivate final @android.annotation.IdRes int mLabel\nclass Attribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
index 37b1778..cc4e9c8 100644
--- a/core/java/android/content/pm/BaseParceledListSlice.java
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -42,8 +42,8 @@
* @hide
*/
abstract class BaseParceledListSlice<T> implements Parcelable {
- private static String TAG = "ParceledListSlice";
- private static boolean DEBUG = false;
+ private static final String TAG = "ParceledListSlice";
+ private static final boolean DEBUG = false;
/*
* TODO get this number from somewhere else. For now set it to a quarter of
diff --git a/core/java/android/content/pm/CapabilityParams.java b/core/java/android/content/pm/CapabilityParams.java
index 7239bac..60e8123 100644
--- a/core/java/android/content/pm/CapabilityParams.java
+++ b/core/java/android/content/pm/CapabilityParams.java
@@ -172,7 +172,7 @@
@NonNull
private final String mKey;
@NonNull
- private String mPrimaryValue;
+ private final String mPrimaryValue;
@NonNull
private Set<String> mAliases;
diff --git a/core/java/android/content/pm/IncrementalStatesInfo.java b/core/java/android/content/pm/IncrementalStatesInfo.java
index f15afdf..7098249 100644
--- a/core/java/android/content/pm/IncrementalStatesInfo.java
+++ b/core/java/android/content/pm/IncrementalStatesInfo.java
@@ -24,8 +24,8 @@
* @hide
*/
public class IncrementalStatesInfo implements Parcelable {
- private boolean mIsLoading;
- private float mProgress;
+ private final boolean mIsLoading;
+ private final float mProgress;
private long mLoadingCompletedTime;
diff --git a/core/java/android/content/pm/KeySet.java b/core/java/android/content/pm/KeySet.java
index fd459e6..3da5bff 100644
--- a/core/java/android/content/pm/KeySet.java
+++ b/core/java/android/content/pm/KeySet.java
@@ -29,7 +29,7 @@
*/
public class KeySet implements Parcelable {
- private IBinder token;
+ private final IBinder token;
/** @hide */
public KeySet(IBinder token) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index d6592d5..3165e29 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1737,7 +1737,8 @@
mCallbacks.add(toAdd);
}
- private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
+ private final IOnAppsChangedListener.Stub mAppsChangedListener =
+ new IOnAppsChangedListener.Stub() {
@Override
public void onPackageRemoved(UserHandle user, String packageName)
@@ -1872,7 +1873,7 @@
private static final int MSG_SHORTCUT_CHANGED = 8;
private static final int MSG_LOADING_PROGRESS_CHANGED = 9;
- private LauncherApps.Callback mCallback;
+ private final LauncherApps.Callback mCallback;
private static class CallbackInfo {
String[] packageNames;
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 2bac066..bb978e0 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -502,6 +502,6 @@
}
private final Collator sCollator = Collator.getInstance();
- private PackageManager mPM;
+ private final PackageManager mPM;
}
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 9114ea3..cdda12e 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -489,7 +489,8 @@
*/
public @Nullable CharSequence nonLocalizedDescription;
- private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class);
+ private static final ForStringSet sForStringSet =
+ Parcelling.Cache.getOrCreate(ForStringSet.class);
/**
* A {@link Set} of trusted signing certificate digests. If this permission has the {@link
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 02a4980..36c03fd 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -586,6 +586,6 @@
}
private final Collator mCollator = Collator.getInstance();
- private PackageManager mPM;
+ private final PackageManager mPM;
}
}
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index c323704..8343c92 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -41,7 +41,7 @@
public static final boolean DEBUG_THROW_ALL_ERRORS = false;
@NonNull
- private Callback mCallback;
+ private final Callback mCallback;
private Object mResult;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0f284f4..cc06ea7 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1419,7 +1419,7 @@
* <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be
* parsed using {@link Locale#forLanguageTag(String)}.
*
- * <p>On SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings
+ * <p>On SDK 20 (Android 4.4W: KitKat for watches) and below, locale strings
* are of the form {@code ll_CC} where {@code ll} is a two letter language code,
* and {@code CC} is a two letter country code.
*/
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 885060f..c3d5b71 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2003,13 +2003,25 @@
private int mHashCode = 0;
- private boolean containsValue(int resId, boolean force) {
+ private int findValue(int resId, boolean force) {
for (int i = 0; i < mCount; ++i) {
if (mResId[i] == resId && mForce[i] == force) {
- return true;
+ return i;
}
}
- return false;
+ return -1;
+ }
+
+ private void moveToLast(int index) {
+ if (index < 0 || index >= mCount - 1) {
+ return;
+ }
+ final int id = mResId[index];
+ final boolean force = mForce[index];
+ System.arraycopy(mResId, index + 1, mResId, index, mCount - index - 1);
+ mResId[mCount - 1] = id;
+ System.arraycopy(mForce, index + 1, mForce, index, mCount - index - 1);
+ mForce[mCount - 1] = force;
}
public void append(int resId, boolean force) {
@@ -2022,15 +2034,17 @@
}
// Some apps tend to keep adding same resources over and over, let's protect from it.
- if (containsValue(resId, force)) {
- return;
+ // Note: the order still matters, as the values that come later override the earlier
+ // ones.
+ final int index = findValue(resId, force);
+ if (index >= 0) {
+ moveToLast(index);
+ } else {
+ mResId = GrowingArrayUtils.append(mResId, mCount, resId);
+ mForce = GrowingArrayUtils.append(mForce, mCount, force);
+ mCount++;
+ mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
}
-
- mResId = GrowingArrayUtils.append(mResId, mCount, resId);
- mForce = GrowingArrayUtils.append(mForce, mCount, force);
- mCount++;
-
- mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteAuthorizer.java b/core/java/android/database/sqlite/SQLiteAuthorizer.java
new file mode 100644
index 0000000..a2bf898
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteAuthorizer.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Authorizer which is consulted during compilation of a SQL statement.
+ * <p>
+ * During compilation, this callback will be invoked to determine if each action
+ * requested by the SQL statement is allowed.
+ * <p>
+ * This can be useful to dynamically block interaction with private, internal,
+ * or otherwise sensitive columns or tables inside a database, such as when
+ * compiling an untrusted SQL statement.
+ */
+public interface SQLiteAuthorizer {
+ /** @hide */
+ @IntDef(prefix = { "SQLITE_AUTHORIZER_RESULT_" }, value = {
+ SQLITE_AUTHORIZER_RESULT_OK,
+ SQLITE_AUTHORIZER_RESULT_DENY,
+ SQLITE_AUTHORIZER_RESULT_IGNORE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AuthorizerResult {}
+
+ /** @hide */
+ @IntDef(prefix = { "SQLITE_ACTION_" }, value = {
+ SQLITE_ACTION_CREATE_INDEX,
+ SQLITE_ACTION_CREATE_TABLE,
+ SQLITE_ACTION_CREATE_TEMP_INDEX,
+ SQLITE_ACTION_CREATE_TEMP_TABLE,
+ SQLITE_ACTION_CREATE_TEMP_TRIGGER,
+ SQLITE_ACTION_CREATE_TEMP_VIEW,
+ SQLITE_ACTION_CREATE_TRIGGER,
+ SQLITE_ACTION_CREATE_VIEW,
+ SQLITE_ACTION_DELETE,
+ SQLITE_ACTION_DROP_INDEX,
+ SQLITE_ACTION_DROP_TABLE,
+ SQLITE_ACTION_DROP_TEMP_INDEX,
+ SQLITE_ACTION_DROP_TEMP_TABLE,
+ SQLITE_ACTION_DROP_TEMP_TRIGGER,
+ SQLITE_ACTION_DROP_TEMP_VIEW,
+ SQLITE_ACTION_DROP_TRIGGER,
+ SQLITE_ACTION_DROP_VIEW,
+ SQLITE_ACTION_INSERT,
+ SQLITE_ACTION_PRAGMA,
+ SQLITE_ACTION_READ,
+ SQLITE_ACTION_SELECT,
+ SQLITE_ACTION_TRANSACTION,
+ SQLITE_ACTION_UPDATE,
+ SQLITE_ACTION_ATTACH,
+ SQLITE_ACTION_DETACH,
+ SQLITE_ACTION_ALTER_TABLE,
+ SQLITE_ACTION_REINDEX,
+ SQLITE_ACTION_ANALYZE,
+ SQLITE_ACTION_CREATE_VTABLE,
+ SQLITE_ACTION_DROP_VTABLE,
+ SQLITE_ACTION_FUNCTION,
+ SQLITE_ACTION_SAVEPOINT,
+ SQLITE_ACTION_RECURSIVE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AuthorizerAction {}
+
+ /** Successful result */
+ int SQLITE_AUTHORIZER_RESULT_OK = 0;
+ /** Abort the SQL statement with an error */
+ int SQLITE_AUTHORIZER_RESULT_DENY = 1;
+ /** Don't allow access, but don't generate an error */
+ int SQLITE_AUTHORIZER_RESULT_IGNORE = 2;
+
+ /** Authorizer action for {@code CREATE INDEX} */
+ int SQLITE_ACTION_CREATE_INDEX = 1;
+ /** Authorizer action for {@code CREATE TABLE} */
+ int SQLITE_ACTION_CREATE_TABLE = 2;
+ /** Authorizer action for {@code CREATE TEMP INDEX} */
+ int SQLITE_ACTION_CREATE_TEMP_INDEX = 3;
+ /** Authorizer action for {@code CREATE TEMP TABLE} */
+ int SQLITE_ACTION_CREATE_TEMP_TABLE = 4;
+ /** Authorizer action for {@code CREATE TEMP TRIGGER} */
+ int SQLITE_ACTION_CREATE_TEMP_TRIGGER = 5;
+ /** Authorizer action for {@code CREATE TEMP VIEW} */
+ int SQLITE_ACTION_CREATE_TEMP_VIEW = 6;
+ /** Authorizer action for {@code CREATE TRIGGER} */
+ int SQLITE_ACTION_CREATE_TRIGGER = 7;
+ /** Authorizer action for {@code CREATE VIEW} */
+ int SQLITE_ACTION_CREATE_VIEW = 8;
+ /** Authorizer action for {@code DELETE} */
+ int SQLITE_ACTION_DELETE = 9;
+ /** Authorizer action for {@code DROP INDEX} */
+ int SQLITE_ACTION_DROP_INDEX = 10;
+ /** Authorizer action for {@code DROP TABLE} */
+ int SQLITE_ACTION_DROP_TABLE = 11;
+ /** Authorizer action for {@code DROP TEMP INDEX} */
+ int SQLITE_ACTION_DROP_TEMP_INDEX = 12;
+ /** Authorizer action for {@code DROP TEMP TABLE} */
+ int SQLITE_ACTION_DROP_TEMP_TABLE = 13;
+ /** Authorizer action for {@code DROP TEMP TRIGGER} */
+ int SQLITE_ACTION_DROP_TEMP_TRIGGER = 14;
+ /** Authorizer action for {@code DROP TEMP VIEW} */
+ int SQLITE_ACTION_DROP_TEMP_VIEW = 15;
+ /** Authorizer action for {@code DROP TRIGGER} */
+ int SQLITE_ACTION_DROP_TRIGGER = 16;
+ /** Authorizer action for {@code DROP VIEW} */
+ int SQLITE_ACTION_DROP_VIEW = 17;
+ /** Authorizer action for {@code INSERT} */
+ int SQLITE_ACTION_INSERT = 18;
+ /** Authorizer action for {@code PRAGMA} */
+ int SQLITE_ACTION_PRAGMA = 19;
+ /** Authorizer action for read access on a specific table and column */
+ int SQLITE_ACTION_READ = 20;
+ /** Authorizer action for {@code SELECT} */
+ int SQLITE_ACTION_SELECT = 21;
+ /** Authorizer action for transaction operations */
+ int SQLITE_ACTION_TRANSACTION = 22;
+ /** Authorizer action for {@code UPDATE} */
+ int SQLITE_ACTION_UPDATE = 23;
+ /** Authorizer action for {@code ATTACH} */
+ int SQLITE_ACTION_ATTACH = 24;
+ /** Authorizer action for {@code DETACH} */
+ int SQLITE_ACTION_DETACH = 25;
+ /** Authorizer action for {@code ALTER TABLE} */
+ int SQLITE_ACTION_ALTER_TABLE = 26;
+ /** Authorizer action for {@code REINDEX} */
+ int SQLITE_ACTION_REINDEX = 27;
+ /** Authorizer action for {@code ANALYZE} */
+ int SQLITE_ACTION_ANALYZE = 28;
+ /** Authorizer action for {@code CREATE VIRTUAL TABLE} */
+ int SQLITE_ACTION_CREATE_VTABLE = 29;
+ /** Authorizer action for {@code DROP VIRTUAL TABLE} */
+ int SQLITE_ACTION_DROP_VTABLE = 30;
+ /** Authorizer action for invocation of a function */
+ int SQLITE_ACTION_FUNCTION = 31;
+ /** Authorizer action for savepoint operations */
+ int SQLITE_ACTION_SAVEPOINT = 32;
+ /** Authorizer action for recursive operations */
+ int SQLITE_ACTION_RECURSIVE = 33;
+
+ /**
+ * Test if the given action should be allowed.
+ *
+ * @param action The action requested by the SQL statement currently being
+ * compiled.
+ * @param arg3 Optional argument relevant to the given action.
+ * @param arg4 Optional argument relevant to the given action.
+ * @param arg5 Optional argument relevant to the given action.
+ * @param arg6 Optional argument relevant to the given action.
+ * @return {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_OK} to allow the action,
+ * {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_IGNORE} to disallow the specific
+ * action but allow the SQL statement to continue to be compiled, or
+ * {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_DENY} to cause the entire SQL
+ * statement to be rejected with an error.
+ * @see <a href="https://www.sqlite.org/c3ref/c_alter_table.html">Upstream
+ * SQLite documentation</a> that describes possible actions and their
+ * arguments.
+ */
+ @AuthorizerResult int onAuthorize(@AuthorizerAction int action, @Nullable String arg3,
+ @Nullable String arg4, @Nullable String arg5, @Nullable String arg6);
+}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 23d4d56..b757cd9 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -17,7 +17,7 @@
package android.database.sqlite;
import android.annotation.NonNull;
-
+import android.annotation.Nullable;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
@@ -33,8 +33,10 @@
import android.util.LruCache;
import android.util.Pair;
import android.util.Printer;
+
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.IOException;
import java.lang.ref.Reference;
@@ -128,9 +130,10 @@
private int mCancellationSignalAttachCount;
private static native long nativeOpen(String path, int openFlags, String label,
- boolean enableTrace, boolean enableProfile, int lookasideSlotSize,
- int lookasideSlotCount);
+ int lookasideSlotSize, int lookasideSlotCount);
private static native void nativeClose(long connectionPtr);
+ private static native void nativeSetAuthorizer(long connectionPtr,
+ SQLiteAuthorizer authorizer);
private static native void nativeRegisterCustomScalarFunction(long connectionPtr,
String name, UnaryOperator<String> function);
private static native void nativeRegisterCustomAggregateFunction(long connectionPtr,
@@ -225,9 +228,7 @@
final String file = mConfiguration.path;
final int cookie = mRecentOperations.beginOperation("open", null, null);
try {
- mConnectionPtr = nativeOpen(file, mConfiguration.openFlags,
- mConfiguration.label,
- NoPreloadHolder.DEBUG_SQL_STATEMENTS, NoPreloadHolder.DEBUG_SQL_TIME,
+ mConnectionPtr = nativeOpen(file, mConfiguration.openFlags, mConfiguration.label,
mConfiguration.lookasideSlotSize, mConfiguration.lookasideSlotCount);
} catch (SQLiteCantOpenDatabaseException e) {
final StringBuilder message = new StringBuilder("Cannot open database '")
@@ -301,9 +302,9 @@
private void setPageSize() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
final long newValue = SQLiteGlobal.getDefaultPageSize();
- long value = executeForLong("PRAGMA page_size", null, null);
+ long value = executeForLong(null, "PRAGMA page_size", null, null);
if (value != newValue) {
- execute("PRAGMA page_size=" + newValue, null, null);
+ execute(null, "PRAGMA page_size=" + newValue, null, null);
}
}
}
@@ -311,9 +312,9 @@
private void setAutoCheckpointInterval() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
final long newValue = SQLiteGlobal.getWALAutoCheckpoint();
- long value = executeForLong("PRAGMA wal_autocheckpoint", null, null);
+ long value = executeForLong(null, "PRAGMA wal_autocheckpoint", null, null);
if (value != newValue) {
- executeForLong("PRAGMA wal_autocheckpoint=" + newValue, null, null);
+ executeForLong(null, "PRAGMA wal_autocheckpoint=" + newValue, null, null);
}
}
}
@@ -321,9 +322,9 @@
private void setJournalSizeLimit() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
final long newValue = SQLiteGlobal.getJournalSizeLimit();
- long value = executeForLong("PRAGMA journal_size_limit", null, null);
+ long value = executeForLong(null, "PRAGMA journal_size_limit", null, null);
if (value != newValue) {
- executeForLong("PRAGMA journal_size_limit=" + newValue, null, null);
+ executeForLong(null, "PRAGMA journal_size_limit=" + newValue, null, null);
}
}
}
@@ -331,9 +332,9 @@
private void setForeignKeyModeFromConfiguration() {
if (!mIsReadOnlyConnection) {
final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0;
- long value = executeForLong("PRAGMA foreign_keys", null, null);
+ long value = executeForLong(null, "PRAGMA foreign_keys", null, null);
if (value != newValue) {
- execute("PRAGMA foreign_keys=" + newValue, null, null);
+ execute(null, "PRAGMA foreign_keys=" + newValue, null, null);
}
}
}
@@ -386,7 +387,7 @@
Log.i(TAG, walFile.getAbsolutePath() + " " + size + " bytes: Bigger than "
+ threshold + "; truncating");
try {
- executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null);
+ executeForString(null, "PRAGMA wal_checkpoint(TRUNCATE)", null, null);
mConfiguration.shouldTruncateWalFile = false;
} catch (SQLiteException e) {
Log.w(TAG, "Failed to truncate the -wal file", e);
@@ -398,10 +399,10 @@
// No change to the sync mode is intended
return;
}
- String value = executeForString("PRAGMA synchronous", null, null);
+ String value = executeForString(null, "PRAGMA synchronous", null, null);
if (!canonicalizeSyncMode(value).equalsIgnoreCase(
canonicalizeSyncMode(newValue))) {
- execute("PRAGMA synchronous=" + newValue, null, null);
+ execute(null, "PRAGMA synchronous=" + newValue, null, null);
}
}
@@ -420,10 +421,11 @@
// No change to the journal mode is intended
return;
}
- String value = executeForString("PRAGMA journal_mode", null, null);
+ String value = executeForString(null, "PRAGMA journal_mode", null, null);
if (!value.equalsIgnoreCase(newValue)) {
try {
- String result = executeForString("PRAGMA journal_mode=" + newValue, null, null);
+ String result = executeForString(null, "PRAGMA journal_mode=" + newValue,
+ null, null);
if (result.equalsIgnoreCase(newValue)) {
return;
}
@@ -475,26 +477,26 @@
try {
// Ensure the android metadata table exists.
- execute("CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)", null, null);
+ execute(null, "CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)", null, null);
// Check whether the locale was actually changed.
- final String oldLocale = executeForString("SELECT locale FROM android_metadata "
+ final String oldLocale = executeForString(null, "SELECT locale FROM android_metadata "
+ "UNION SELECT NULL ORDER BY locale DESC LIMIT 1", null, null);
if (oldLocale != null && oldLocale.equals(newLocale)) {
return;
}
// Go ahead and update the indexes using the new locale.
- execute("BEGIN", null, null);
+ execute(null, "BEGIN", null, null);
boolean success = false;
try {
- execute("DELETE FROM android_metadata", null, null);
- execute("INSERT INTO android_metadata (locale) VALUES(?)",
+ execute(null, "DELETE FROM android_metadata", null, null);
+ execute(null, "INSERT INTO android_metadata (locale) VALUES(?)",
new Object[] { newLocale }, null);
- execute("REINDEX LOCALIZED", null, null);
+ execute(null, "REINDEX LOCALIZED", null, null);
success = true;
} finally {
- execute(success ? "COMMIT" : "ROLLBACK", null, null);
+ execute(null, success ? "COMMIT" : "ROLLBACK", null, null);
}
} catch (SQLiteException ex) {
throw ex;
@@ -523,10 +525,10 @@
final int type = DatabaseUtils.getSqlStatementType(statement.first);
switch (type) {
case DatabaseUtils.STATEMENT_SELECT:
- executeForString(statement.first, statement.second, null);
+ executeForString(null, statement.first, statement.second, null);
break;
case DatabaseUtils.STATEMENT_PRAGMA:
- execute(statement.first, statement.second, null);
+ execute(null, statement.first, statement.second, null);
break;
default:
throw new IllegalArgumentException(
@@ -543,9 +545,10 @@
final File checkFile = new File(mConfiguration.path
+ SQLiteGlobal.WIPE_CHECK_FILE_SUFFIX);
- final boolean hasMetadataTable = executeForLong(
+ final boolean hasMetadataTable = executeForLong(null,
"SELECT count(*) FROM sqlite_master"
- + " WHERE type='table' AND name='android_metadata'", null, null) > 0;
+ + " WHERE type='table' AND name='android_metadata'",
+ null, null) > 0;
final boolean hasCheckFile = checkFile.exists();
if (!mIsReadOnlyConnection && !hasCheckFile) {
@@ -580,6 +583,10 @@
final int oldSize = mConfiguration.perConnectionSql.size();
final int newSize = configuration.perConnectionSql.size();
boolean perConnectionSqlChanged = newSize > oldSize;
+ boolean journalModeChanged = !configuration.resolveJournalMode().equalsIgnoreCase(
+ mConfiguration.resolveJournalMode());
+ boolean syncModeChanged =
+ !configuration.resolveSyncMode().equalsIgnoreCase(mConfiguration.resolveSyncMode());
// Update configuration parameters.
mConfiguration.updateParametersFrom(configuration);
@@ -591,14 +598,10 @@
setForeignKeyModeFromConfiguration();
}
- boolean journalModeChanged = !configuration.resolveJournalMode().equalsIgnoreCase(
- mConfiguration.resolveJournalMode());
if (journalModeChanged) {
setJournalFromConfiguration();
}
- boolean syncModeChanged =
- !configuration.resolveSyncMode().equalsIgnoreCase(mConfiguration.resolveSyncMode());
if (syncModeChanged) {
setSyncModeFromConfiguration();
}
@@ -667,14 +670,15 @@
*
* @throws SQLiteException if an error occurs, such as a syntax error.
*/
- public void prepare(String sql, SQLiteStatementInfo outStatementInfo) {
+ public void prepare(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable SQLiteStatementInfo outStatementInfo) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
final int cookie = mRecentOperations.beginOperation("prepare", sql, null);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
if (outStatementInfo != null) {
outStatementInfo.numParameters = statement.mNumParameters;
@@ -714,8 +718,9 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public void execute(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public void execute(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -724,7 +729,7 @@
try {
final boolean isPragmaStmt =
DatabaseUtils.getSqlStatementType(sql) == DatabaseUtils.STATEMENT_PRAGMA;
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -759,15 +764,15 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLong(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public long executeForLong(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable Object[] bindArgs, @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -804,15 +809,15 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public String executeForString(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public String executeForString(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable Object[] bindArgs, @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -851,8 +856,9 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public ParcelFileDescriptor executeForBlobFileDescriptor(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -860,7 +866,7 @@
final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor",
sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -897,8 +903,9 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForChangedRowCount(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public int executeForChangedRowCount(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -907,7 +914,7 @@
final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount",
sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -946,8 +953,9 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
- CancellationSignal cancellationSignal) {
+ public long executeForLastInsertedRowId(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -955,7 +963,7 @@
final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId",
sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -1000,9 +1008,10 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForCursorWindow(String sql, Object[] bindArgs,
- CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
- CancellationSignal cancellationSignal) {
+ public int executeForCursorWindow(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable Object[] bindArgs, @NonNull CursorWindow window,
+ int startPos, int requiredPos, boolean countAllRows,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -1018,7 +1027,7 @@
final int cookie = mRecentOperations.beginOperation("executeForCursorWindow",
sql, bindArgs);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
@@ -1056,13 +1065,19 @@
}
}
+
/**
* Return a {@link #PreparedStatement}, possibly from the cache.
*/
- PreparedStatement acquirePreparedStatement(String sql) {
+ private PreparedStatement acquirePreparedStatement(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql) {
++mPool.mTotalPrepareStatements;
- PreparedStatement statement = mPreparedStatementCache.get(sql);
- boolean skipCache = false;
+ // Custom per-statement authorizers are typically used for incoming
+ // untrusted custom SQL, which is likely to have low cache hit ratios,
+ // so we compile them every time. This leaves the prepared statement
+ // cache for statements using the default authorizer.
+ boolean skipCache = (authorizer != null);
+ PreparedStatement statement = skipCache ? null : mPreparedStatementCache.get(sql);
if (statement != null) {
if (!statement.mInUse) {
return statement;
@@ -1073,8 +1088,12 @@
skipCache = true;
}
++mPool.mTotalPrepareStatementCacheMiss;
- final long statementPtr = nativePrepareStatement(mConnectionPtr, sql);
+ if (authorizer != null) {
+ nativeSetAuthorizer(mConnectionPtr, authorizer);
+ }
+ long statementPtr = 0;
try {
+ statementPtr = nativePrepareStatement(mConnectionPtr, sql);
final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr);
final int type = DatabaseUtils.getSqlStatementType(sql);
final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr);
@@ -1086,10 +1105,15 @@
} catch (RuntimeException ex) {
// Finalize the statement if an exception occurred and we did not add
// it to the cache. If it is already in the cache, then leave it there.
+ // It is safe to call finalize on a NULL, if nativePrepare failed.
if (statement == null || !statement.mInCache) {
nativeFinalizeStatement(mConnectionPtr, statementPtr);
}
throw ex;
+ } finally {
+ if (authorizer != null) {
+ nativeSetAuthorizer(mConnectionPtr, null);
+ }
}
statement.mInUse = true;
return statement;
@@ -1130,10 +1154,11 @@
* Return a prepared statement for use by {@link SQLiteRawStatement}. This throws if the
* prepared statement is incompatible with this connection.
*/
- PreparedStatement acquirePersistentStatement(@NonNull String sql) {
+ PreparedStatement acquirePersistentStatement(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql) {
final int cookie = mRecentOperations.beginOperation("prepare", sql, null);
try {
- final PreparedStatement statement = acquirePreparedStatement(sql);
+ final PreparedStatement statement = acquirePreparedStatement(authorizer, sql);
throwIfStatementForbidden(statement);
return statement;
} catch (RuntimeException e) {
@@ -1328,8 +1353,8 @@
long pageCount = 0;
long pageSize = 0;
try {
- pageCount = executeForLong("PRAGMA page_count;", null, null);
- pageSize = executeForLong("PRAGMA page_size;", null, null);
+ pageCount = executeForLong(null, "PRAGMA page_count;", null, null);
+ pageSize = executeForLong(null, "PRAGMA page_size;", null, null);
} catch (SQLiteException ex) {
// Ignore.
}
@@ -1340,15 +1365,15 @@
// the main database which we have already described.
CursorWindow window = new CursorWindow("collectDbStats");
try {
- executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null);
+ executeForCursorWindow(null, "PRAGMA database_list;", null, window, 0, 0, false, null);
for (int i = 1; i < window.getNumRows(); i++) {
String name = window.getString(i, 1);
String path = window.getString(i, 2);
pageCount = 0;
pageSize = 0;
try {
- pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null);
- pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null);
+ pageCount = executeForLong(null, "PRAGMA " + name + ".page_count;", null, null);
+ pageSize = executeForLong(null, "PRAGMA " + name + ".page_size;", null, null);
} catch (SQLiteException ex) {
// Ignore.
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 8391865..06d4f28 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -44,10 +44,12 @@
import android.util.Log;
import android.util.Pair;
import android.util.Printer;
+
import com.android.internal.util.Preconditions;
import dalvik.annotation.optimization.NeverCompile;
import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
@@ -253,6 +255,13 @@
*/
public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
+ /** @hide */
+ public static final int ENABLE_TRACE = 0x00000100;
+ /** @hide */
+ public static final int ENABLE_PROFILE = 0x00000200;
+ /** @hide */
+ public static final int ENABLE_AUTHORIZER = 0x00000400;
+
/**
* Open flag: Flag for {@link #openDatabase} to create the database file if it does not
* already exist.
@@ -1453,9 +1462,38 @@
* {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
*/
public SQLiteStatement compileStatement(String sql) throws SQLException {
+ return compileStatementInternal(sql, null);
+ }
+
+ /**
+ * Compiles an SQL statement into a reusable pre-compiled statement object.
+ * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
+ * statement and fill in those values with {@link SQLiteProgram#bindString}
+ * and {@link SQLiteProgram#bindLong} each time you want to run the
+ * statement. Statements may not return result sets larger than 1x1.
+ *<p>
+ * No two threads should be using the same {@link SQLiteStatement} at the same time.
+ * Must configure: {@link OpenParams.Builder#setAuthorizerSupportEnabled(boolean)}.
+ *
+ * @param sql The raw SQL statement, may contain ? for unknown values to be
+ * bound later.
+ * @param authorizer The sql authorizer attached to the statement.
+ * @return A pre-compiled {@link SQLiteStatement} object. Note that
+ * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
+ */
+ public @NonNull SQLiteStatement compileStatement(@NonNull String sql,
+ @NonNull SQLiteAuthorizer authorizer) throws SQLException {
+ return compileStatementInternal(sql, authorizer);
+ }
+
+ private @NonNull SQLiteStatement compileStatementInternal(@NonNull String sql,
+ @Nullable SQLiteAuthorizer authorizer) throws SQLException {
+ if (authorizer != null) {
+ throwIfNotAuthorizerEnabled();
+ }
acquireReference();
try {
- return new SQLiteStatement(this, sql, null);
+ return new SQLiteStatement(this, authorizer, sql, null);
} finally {
releaseReference();
}
@@ -1752,7 +1790,8 @@
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable) {
- return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
+ return rawQueryWithFactoryInternal(cursorFactory, sql, selectionArgs,
+ editTable, null, null);
}
/**
@@ -1773,17 +1812,52 @@
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
+ return rawQueryWithFactoryInternal(cursorFactory, sql, selectionArgs, editTable,
+ cancellationSignal, null);
+ }
+
+ /**
+ * Runs the provided SQL and returns a cursor over the result set.
+ * Must configure: {@link OpenParams.Builder#setAuthorizerSupportEnabled(boolean)}.
+ *
+ * @param cursorFactory the cursor factory to use, or null for the default factory
+ * @param sql the SQL query. The SQL string must not be ; terminated
+ * @param selectionArgs You may include ?s in where clause in the query,
+ * which will be replaced by the values from selectionArgs. The
+ * values will be bound as Strings.
+ * @param editTable the name of the first table, which is editable
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @param authorizer The sql authorizer attached to the query.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ */
+ public @NonNull Cursor rawQueryWithFactory(@Nullable CursorFactory cursorFactory,
+ @NonNull String sql, @SuppressLint("ArrayReturn") @Nullable String[] selectionArgs,
+ @Nullable String editTable, @Nullable CancellationSignal cancellationSignal,
+ @NonNull SQLiteAuthorizer authorizer) {
+ return rawQueryWithFactoryInternal(cursorFactory, sql, selectionArgs, editTable,
+ cancellationSignal, authorizer);
+ }
+
+ private @NonNull Cursor rawQueryWithFactoryInternal(@Nullable CursorFactory cursorFactory,
+ @NonNull String sql, @SuppressLint("ArrayReturn") @Nullable String[] selectionArgs,
+ @Nullable String editTable, @Nullable CancellationSignal cancellationSignal,
+ @Nullable SQLiteAuthorizer authorizer) {
+ if (authorizer != null) {
+ throwIfNotAuthorizerEnabled();
+ }
acquireReference();
try {
- SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
- cancellationSignal);
+ SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, authorizer, sql,
+ editTable, cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}
-
/**
* Convenience method for inserting a row into the database.
*
@@ -1931,7 +2005,8 @@
}
sql.append(')');
- SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
+ // Custom authorizers can be applied through SQLiteQueryBuilder
+ SQLiteStatement statement = new SQLiteStatement(this, null, sql.toString(), bindArgs);
try {
return statement.executeInsert();
} finally {
@@ -1958,8 +2033,9 @@
public int delete(String table, String whereClause, String[] whereArgs) {
acquireReference();
try {
- SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
- (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
+ // Custom authorizers can be applied through SQLiteQueryBuilder
+ SQLiteStatement statement = new SQLiteStatement(this, null, "DELETE FROM " + table
+ + (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
try {
return statement.executeUpdateDelete();
} finally {
@@ -2036,7 +2112,8 @@
sql.append(whereClause);
}
- SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
+ // Custom authorizers can be applied through SQLiteQueryBuilder
+ SQLiteStatement statement = new SQLiteStatement(this, null, sql.toString(), bindArgs);
try {
return statement.executeUpdateDelete();
} finally {
@@ -2073,7 +2150,7 @@
* @throws SQLException if the SQL string is invalid
*/
public void execSQL(String sql) throws SQLException {
- executeSql(sql, null);
+ executeSql(null, sql, null);
}
/**
@@ -2126,14 +2203,72 @@
* @throws SQLException if the SQL string is invalid
*/
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
- if (bindArgs == null) {
- throw new IllegalArgumentException("Empty bindArgs");
+ executeSql(null, sql, bindArgs);
+ }
+
+ /**
+ * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
+ * Must configure: {@link OpenParams.Builder#setAuthorizerSupportEnabled(boolean)}.
+ * <p>
+ * For INSERT statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #insert(String, String, ContentValues)}</li>
+ * <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
+ * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
+ * </ul>
+ * <p>
+ * For UPDATE statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #update(String, ContentValues, String, String[])}</li>
+ * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
+ * </ul>
+ * <p>
+ * For DELETE statements, use any of the following instead.
+ * <ul>
+ * <li>{@link #delete(String, String, String[])}</li>
+ * </ul>
+ * <p>
+ * For example, the following are good candidates for using this method:
+ * <ul>
+ * <li>ALTER TABLE</li>
+ * <li>CREATE or DROP table / trigger / view / index / virtual table</li>
+ * <li>REINDEX</li>
+ * <li>RELEASE</li>
+ * <li>SAVEPOINT</li>
+ * <li>PRAGMA that returns no data</li>
+ * </ul>
+ * </p>
+ * <p>
+ * When using {@link #enableWriteAheadLogging()}, journal_mode is
+ * automatically managed by this class. So, do not set journal_mode
+ * using "PRAGMA journal_mode'<value>" statement if your app is using
+ * {@link #enableWriteAheadLogging()}
+ * </p>
+ * <p>
+ * Note that {@code PRAGMA} values which apply on a per-connection basis
+ * should <em>not</em> be configured using this method; you should instead
+ * use {@link #execPerConnectionSQL} to ensure that they are uniformly
+ * applied to all current and future connections.
+ * </p>
+ *
+ * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
+ * not supported.
+ * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
+ * @param authorizer The sql authorizer attached to the query.
+ * @throws SQLException if the SQL string is invalid
+ */
+ public void execSQL(@NonNull String sql,
+ @SuppressLint("ArrayReturn") @Nullable Object[] bindArgs,
+ @NonNull SQLiteAuthorizer authorizer) throws SQLException {
+ if (authorizer != null) {
+ throwIfNotAuthorizerEnabled();
}
- executeSql(sql, bindArgs);
+ executeSql(authorizer, sql, bindArgs);
}
/** {@hide} */
- public int executeSql(String sql, Object[] bindArgs) throws SQLException {
+ public int executeSql(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable Object[] bindArgs) throws SQLException {
acquireReference();
try {
final int statementType = DatabaseUtils.getSqlStatementType(sql);
@@ -2151,7 +2286,7 @@
}
}
- try (SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs)) {
+ try (SQLiteStatement statement = new SQLiteStatement(this, authorizer, sql, bindArgs)) {
return statement.executeUpdateDelete();
} finally {
// If schema was updated, close non-primary connections, otherwise they might
@@ -2169,6 +2304,25 @@
* Return a {@link SQLiteRawStatement} connected to the database. A transaction must be in
* progress or an exception will be thrown. The resulting object will be closed automatically
* when the current transaction closes.
+ * Must configure: {@link OpenParams.Builder#setAuthorizerSupportEnabled(boolean)}.
+ * @param sql The SQL string to be compiled into a prepared statement.
+ * @param authorizer The sql authorizer attached to the statement.
+ * @return A {@link SQLiteRawStatement} holding the compiled SQL.
+ * @throws IllegalStateException if a transaction is not in progress.
+ * @throws SQLiteException if the SQL cannot be compiled.
+ * @hide
+ */
+ @NonNull
+ public SQLiteRawStatement createRawStatement(@NonNull String sql,
+ @NonNull SQLiteAuthorizer authorizer) {
+ Objects.requireNonNull(sql);
+ return new SQLiteRawStatement(this, sql, authorizer);
+ }
+
+ /**
+ * Return a {@link SQLiteRawStatement} connected to the database. A transaction must be in
+ * progress or an exception will be thrown. The resulting object will be closed automatically
+ * when the current transaction closes.
* @param sql The SQL string to be compiled into a prepared statement.
* @return A {@link SQLiteRawStatement} holding the compiled SQL.
* @throws IllegalStateException if a transaction is not in progress.
@@ -2178,9 +2332,8 @@
@NonNull
public SQLiteRawStatement createRawStatement(@NonNull String sql) {
Objects.requireNonNull(sql);
- return new SQLiteRawStatement(this, sql);
+ return createRawStatement(sql, null);
}
-
/**
* Return the "rowid" of the last row to be inserted on the current connection. See the
* SQLite documentation for the specific details. This method must only be called when inside
@@ -2206,7 +2359,33 @@
* @throws SQLiteException if {@code sql} is invalid
*/
public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal) {
- getThreadSession().prepare(sql,
+ validateSqlInternal(sql, cancellationSignal, null);
+ }
+
+ /**
+ * Verifies that a SQL SELECT statement is valid by compiling it.
+ * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
+ * Must configure: {@link OpenParams.Builder#setAuthorizerSupportEnabled(boolean)}.
+ *
+ * @param sql SQL to be validated
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @param authorizer The sql authorizer attached to the query.
+ * @throws SQLiteException if {@code sql} is invalid
+ */
+ public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal,
+ @NonNull SQLiteAuthorizer authorizer) {
+ validateSqlInternal(sql, cancellationSignal, authorizer);
+ }
+
+ private void validateSqlInternal(@NonNull String sql,
+ @Nullable CancellationSignal cancellationSignal,
+ @Nullable SQLiteAuthorizer authorizer) {
+ if (authorizer != null) {
+ throwIfNotAuthorizerEnabled();
+ }
+ getThreadSession().prepare(authorizer, sql,
getThreadDefaultConnectionFlags(/* readOnly =*/ true), cancellationSignal, null);
}
@@ -2226,6 +2405,21 @@
}
/**
+ * Returns true if the database is opened with authorizer support enabled.
+ *
+ * @return True if authorizer support is enabled.
+ */
+ public boolean isAuthorizerSupportEnabled() {
+ synchronized (mLock) {
+ return isAuthorizerSupportEnabledLocked();
+ }
+ }
+
+ private boolean isAuthorizerSupportEnabledLocked() {
+ return (mConfigurationLocked.openFlags & ENABLE_AUTHORIZER) != 0;
+ }
+
+ /**
* Returns true if the database is in-memory db.
*
* @return True if the database is in-memory.
@@ -2810,6 +3004,13 @@
return "SQLiteDatabase: " + getPath();
}
+ private void throwIfNotAuthorizerEnabled() {
+ if ((mConfigurationLocked.openFlags & ENABLE_AUTHORIZER) == 0) {
+ throw new IllegalStateException("The database '" + mConfigurationLocked.label
+ + "' does not have authorizer support enabled.");
+ }
+ }
+
private void throwIfNotOpenLocked() {
if (mConnectionPoolLocked == null) {
throw new IllegalStateException("The database '" + mConfigurationLocked.label
@@ -3074,6 +3275,39 @@
}
/**
+ * Returns if support for {@link SQLiteAuthorizer} is enabled.
+ *
+ * @see SQLiteDatabase#compileStatement(String, SQLiteAuthorizer)
+ * @see SQLiteDatabase#execSQL(String, Object[], SQLiteAuthorizer)
+ * @see SQLiteDatabase#validateSql(String, CancellationSignal,
+ * SQLiteAuthorizer)
+ * @see SQLiteDatabase#rawQueryWithFactory(CursorFactory, String,
+ * String[], String, CancellationSignal, SQLiteAuthorizer)
+ */
+ public boolean isAuthorizerSupportEnabled() {
+ return (mOpenFlags & ENABLE_AUTHORIZER) != 0;
+ }
+
+ /**
+ * Enables or disables support for {@link SQLiteAuthorizer}.
+ *
+ * @see SQLiteDatabase#compileStatement(String, SQLiteAuthorizer)
+ * @see SQLiteDatabase#execSQL(String, Object[], SQLiteAuthorizer)
+ * @see SQLiteDatabase#validateSql(String, CancellationSignal,
+ * SQLiteAuthorizer)
+ * @see SQLiteDatabase#rawQueryWithFactory(CursorFactory, String,
+ * String[], String, CancellationSignal, SQLiteAuthorizer)
+ */
+ public @NonNull Builder setAuthorizerSupportEnabled(boolean enabled) {
+ if (enabled) {
+ addOpenFlags(SQLiteDatabase.ENABLE_AUTHORIZER);
+ } else {
+ removeOpenFlags(SQLiteDatabase.ENABLE_AUTHORIZER);
+ }
+ return this;
+ }
+
+ /**
* Set an optional factory class that is called to instantiate a cursor when query
* is called.
*
@@ -3174,7 +3408,8 @@
OPEN_READONLY,
CREATE_IF_NECESSARY,
NO_LOCALIZED_COLLATORS,
- ENABLE_WRITE_AHEAD_LOGGING
+ ENABLE_WRITE_AHEAD_LOGGING,
+ ENABLE_AUTHORIZER
})
@Retention(RetentionPolicy.SOURCE)
public @interface DatabaseOpenFlags {}
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index bc63686..63b59f7 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -17,9 +17,11 @@
package android.database.sqlite;
import android.compat.annotation.UnsupportedAppUsage;
+import android.database.sqlite.SQLiteDebug.NoPreloadHolder;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Pair;
+
import java.util.ArrayList;
import java.util.Locale;
import java.util.function.BinaryOperator;
@@ -155,6 +157,13 @@
throw new IllegalArgumentException("path must not be null.");
}
+ if (NoPreloadHolder.DEBUG_SQL_STATEMENTS) {
+ openFlags |= SQLiteDatabase.ENABLE_PROFILE;
+ }
+ if (NoPreloadHolder.DEBUG_SQL_TIME) {
+ openFlags |= SQLiteDatabase.ENABLE_TRACE;
+ }
+
this.path = path;
label = stripPathForLogs(path);
this.openFlags = openFlags;
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index 1721e0c..8be11d0 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -29,6 +31,7 @@
@TestApi
public final class SQLiteDirectCursorDriver implements SQLiteCursorDriver {
private final SQLiteDatabase mDatabase;
+ private final SQLiteAuthorizer mAuthorizer;
private final String mEditTable;
private final String mSql;
private final CancellationSignal mCancellationSignal;
@@ -36,14 +39,22 @@
public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
CancellationSignal cancellationSignal) {
+ this(db, null, sql, editTable, cancellationSignal);
+ }
+
+ public SQLiteDirectCursorDriver(@NonNull SQLiteDatabase db,
+ @Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable String editTable, @Nullable CancellationSignal cancellationSignal) {
mDatabase = db;
+ mAuthorizer = authorizer;
mEditTable = editTable;
mSql = sql;
mCancellationSignal = cancellationSignal;
}
public Cursor query(CursorFactory factory, String[] selectionArgs) {
- final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
+ final SQLiteQuery query = new SQLiteQuery(mDatabase,
+ mAuthorizer, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index cd4131c..84b2a8a 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.database.DatabaseUtils;
import android.os.Build;
@@ -33,6 +35,7 @@
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final SQLiteDatabase mDatabase;
+ private final SQLiteAuthorizer mAuthorizer;
@UnsupportedAppUsage
private final String mSql;
private final boolean mReadOnly;
@@ -41,9 +44,11 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private final Object[] mBindArgs;
- SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
- CancellationSignal cancellationSignalForPrepare) {
+ SQLiteProgram(@NonNull SQLiteDatabase db, @Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs,
+ @Nullable CancellationSignal cancellationSignalForPrepare) {
mDatabase = db;
+ mAuthorizer = authorizer;
mSql = sql.trim();
int n = DatabaseUtils.getSqlStatementType(mSql);
@@ -59,7 +64,7 @@
default:
boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
SQLiteStatementInfo info = new SQLiteStatementInfo();
- db.getThreadSession().prepare(mSql,
+ db.getThreadSession().prepare(mAuthorizer, mSql,
db.getThreadDefaultConnectionFlags(assumeReadOnly),
cancellationSignalForPrepare, info);
mReadOnly = info.readOnly;
@@ -88,6 +93,10 @@
return mDatabase;
}
+ final SQLiteAuthorizer getAuthorizer() {
+ return mAuthorizer;
+ }
+
final String getSql() {
return mSql;
}
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 62bcc20..1d23193 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.database.CursorWindow;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
@@ -33,8 +35,9 @@
private final CancellationSignal mCancellationSignal;
- SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
- super(db, query, null, cancellationSignal);
+ SQLiteQuery(@NonNull SQLiteDatabase db, @Nullable SQLiteAuthorizer authorizer,
+ @NonNull String query, @Nullable CancellationSignal cancellationSignal) {
+ super(db, authorizer, query, null, cancellationSignal);
mCancellationSignal = cancellationSignal;
}
@@ -59,9 +62,9 @@
try {
window.acquireReference();
try {
- int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
- window, startPos, requiredPos, countAllRows, getConnectionFlags(),
- mCancellationSignal);
+ int numRows = getSession().executeForCursorWindow(getAuthorizer(), getSql(),
+ getBindArgs(), window, startPos, requiredPos, countAllRows,
+ getConnectionFlags(), mCancellationSignal);
return numRows;
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
diff --git a/core/java/android/database/sqlite/SQLiteRawStatement.java b/core/java/android/database/sqlite/SQLiteRawStatement.java
index 6b43788..6c1ec39 100644
--- a/core/java/android/database/sqlite/SQLiteRawStatement.java
+++ b/core/java/android/database/sqlite/SQLiteRawStatement.java
@@ -20,8 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
-
import dalvik.annotation.optimization.FastNative;
import java.io.Closeable;
@@ -138,14 +136,15 @@
* {@link IllegalStateException} if a transaction is not in progress. Clients should call
* {@link SQLiteDatabase.createRawStatement} to create a new instance.
*/
- SQLiteRawStatement(@NonNull SQLiteDatabase db, @NonNull String sql) throws SQLiteException {
+ SQLiteRawStatement(@NonNull SQLiteDatabase db, @NonNull String sql,
+ @Nullable SQLiteAuthorizer authorizer) throws SQLiteException {
mThread = Thread.currentThread();
mDatabase = db;
mSession = mDatabase.getThreadSession();
mSession.throwIfNoTransaction();
mSql = sql;
// Acquire a connection and prepare the statement.
- mPreparedStatement = mSession.acquirePersistentStatement(mSql, this);
+ mPreparedStatement = mSession.acquirePersistentStatement(authorizer, mSql, this);
mStatement = mPreparedStatement.mStatementPtr;
}
diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java
index 2379c84..936ff34 100644
--- a/core/java/android/database/sqlite/SQLiteSession.java
+++ b/core/java/android/database/sqlite/SQLiteSession.java
@@ -17,7 +17,7 @@
package android.database.sqlite;
import android.annotation.NonNull;
-
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
@@ -80,7 +80,7 @@
* specifying the desired transaction mode. Once an explicit transaction has begun,
* all subsequent database operations will be performed as part of that transaction.
* To end an explicit transaction, first call {@link #setTransactionSuccessful} if the
- * transaction was successful, then call {@link #end}. If the transaction was
+ * transaction was successful, then call {@link #endTransaction}. If the transaction was
* marked successful, its changes will be committed, otherwise they will be rolled back.
* </p><p>
* Explicit transactions can also be nested. A nested explicit transaction is
@@ -309,12 +309,12 @@
CancellationSignal cancellationSignal) {
throwIfTransactionMarkedSuccessful();
beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
- cancellationSignal);
+ cancellationSignal);
}
private void beginTransactionUnchecked(int transactionMode,
SQLiteTransactionListener transactionListener, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ @Nullable CancellationSignal cancellationSignal) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
@@ -329,20 +329,21 @@
// Execute SQL might throw a runtime exception.
switch (transactionMode) {
case TRANSACTION_MODE_IMMEDIATE:
- mConnection.execute("BEGIN IMMEDIATE;", null,
+ mConnection.execute(null, "BEGIN IMMEDIATE;", null,
cancellationSignal); // might throw
break;
case TRANSACTION_MODE_EXCLUSIVE:
- mConnection.execute("BEGIN EXCLUSIVE;", null,
+ mConnection.execute(null, "BEGIN EXCLUSIVE;", null,
cancellationSignal); // might throw
break;
case TRANSACTION_MODE_DEFERRED:
- mConnection.execute("BEGIN DEFERRED;", null,
+ mConnection.execute(null, "BEGIN DEFERRED;", null,
cancellationSignal); // might throw
break;
default:
// Per SQLite documentation, this executes in DEFERRED mode.
- mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
+ mConnection.execute(null, "BEGIN;",
+ null, cancellationSignal); // might throw
break;
}
}
@@ -353,7 +354,8 @@
transactionListener.onBegin(); // might throw
} catch (RuntimeException ex) {
if (mTransactionStack == null) {
- mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
+ mConnection.execute(null, "ROLLBACK;", null,
+ cancellationSignal); // might throw
}
throw ex;
}
@@ -415,14 +417,14 @@
* @see #setTransactionSuccessful
* @see #yieldTransaction
*/
- public void endTransaction(CancellationSignal cancellationSignal) {
+ public void endTransaction(@Nullable CancellationSignal cancellationSignal) {
throwIfNoTransaction();
assert mConnection != null;
-
endTransactionUnchecked(cancellationSignal, false);
}
- private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
+ private void endTransactionUnchecked(@Nullable CancellationSignal cancellationSignal,
+ boolean yielding) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
@@ -460,9 +462,11 @@
try {
if (successful) {
- mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
+ mConnection.execute(null, "COMMIT;", null,
+ cancellationSignal); // might throw
} else {
- mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
+ mConnection.execute(null, "ROLLBACK;", null,
+ cancellationSignal); // might throw
}
} finally {
releaseConnection(); // might throw
@@ -599,8 +603,9 @@
* @throws SQLiteException if an error occurs, such as a syntax error.
* @throws OperationCanceledException if the operation was canceled.
*/
- public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
- SQLiteStatementInfo outStatementInfo) {
+ public void prepare(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ int connectionFlags, @Nullable CancellationSignal cancellationSignal,
+ @Nullable SQLiteStatementInfo outStatementInfo) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -611,7 +616,7 @@
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- mConnection.prepare(sql, outStatementInfo); // might throw
+ mConnection.prepare(authorizer, sql, outStatementInfo); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -630,19 +635,20 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public void execute(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ public void execute(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
+ mConnection.execute(authorizer, sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -663,19 +669,21 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ public long executeForLong(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
+ return mConnection.executeForLong(authorizer, sql, bindArgs,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -696,19 +704,21 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ public String executeForString(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return null;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
+ return mConnection.executeForString(authorizer, sql, bindArgs,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -731,19 +741,20 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
- int connectionFlags, CancellationSignal cancellationSignal) {
+ public ParcelFileDescriptor executeForBlobFileDescriptor(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return null;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
+ return mConnection.executeForBlobFileDescriptor(authorizer, sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
@@ -765,19 +776,20 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ public int executeForChangedRowCount(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForChangedRowCount(sql, bindArgs,
+ return mConnection.executeForChangedRowCount(authorizer, sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
@@ -799,19 +811,20 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ public long executeForLastInsertedRowId(@Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForLastInsertedRowId(sql, bindArgs,
+ return mConnection.executeForLastInsertedRowId(authorizer, sql, bindArgs,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
@@ -842,9 +855,10 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForCursorWindow(String sql, Object[] bindArgs,
- CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
- int connectionFlags, CancellationSignal cancellationSignal) {
+ public int executeForCursorWindow(@Nullable SQLiteAuthorizer authorizer, @NonNull String sql,
+ @Nullable Object[] bindArgs, @NonNull CursorWindow window, int startPos,
+ int requiredPos, boolean countAllRows, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -852,14 +866,14 @@
throw new IllegalArgumentException("window must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
+ if (executeSpecial(sql, connectionFlags, cancellationSignal)) {
window.clear();
return 0;
}
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForCursorWindow(sql, bindArgs,
+ return mConnection.executeForCursorWindow(authorizer, sql, bindArgs,
window, startPos, requiredPos, countAllRows,
cancellationSignal); // might throw
} finally {
@@ -888,8 +902,8 @@
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
- private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
- CancellationSignal cancellationSignal) {
+ private boolean executeSpecial(@NonNull String sql, int connectionFlags,
+ @Nullable CancellationSignal cancellationSignal) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
@@ -942,13 +956,14 @@
* method is called when the transaction is closed.
*/
@NonNull
- SQLiteConnection.PreparedStatement acquirePersistentStatement(@NonNull String query,
- @NonNull Closeable dependent) {
+ SQLiteConnection.PreparedStatement acquirePersistentStatement(
+ @Nullable SQLiteAuthorizer authorizer,
+ @NonNull String query, @NonNull Closeable dependent) {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
mOpenDependents.addFirst(dependent);
try {
- return mConnection.acquirePersistentStatement(query);
+ return mConnection.acquirePersistentStatement(authorizer, query);
} catch (Throwable e) {
mOpenDependents.remove(dependent);
throw e;
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index acdc0fa..82023c7 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.ParcelFileDescriptor;
@@ -32,7 +34,12 @@
public final class SQLiteStatement extends SQLiteProgram {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) {
- super(db, sql, bindArgs, null);
+ super(db, null, sql, bindArgs, null);
+ }
+
+ SQLiteStatement(@NonNull SQLiteDatabase db, @Nullable SQLiteAuthorizer authorizer,
+ @NonNull String sql, @Nullable Object[] bindArgs) {
+ super(db, authorizer, sql, bindArgs, null);
}
/**
@@ -45,7 +52,8 @@
public void execute() {
acquireReference();
try {
- getSession().execute(getSql(), getBindArgs(), getConnectionFlags(), null);
+ getSession().execute(
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -66,7 +74,7 @@
acquireReference();
try {
return getSession().executeForChangedRowCount(
- getSql(), getBindArgs(), getConnectionFlags(), null);
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -88,7 +96,7 @@
acquireReference();
try {
return getSession().executeForLastInsertedRowId(
- getSql(), getBindArgs(), getConnectionFlags(), null);
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -109,7 +117,7 @@
acquireReference();
try {
return getSession().executeForLong(
- getSql(), getBindArgs(), getConnectionFlags(), null);
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -130,7 +138,7 @@
acquireReference();
try {
return getSession().executeForString(
- getSql(), getBindArgs(), getConnectionFlags(), null);
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -151,7 +159,7 @@
acquireReference();
try {
return getSession().executeForBlobFileDescriptor(
- getSql(), getBindArgs(), getConnectionFlags(), null);
+ getAuthorizer(), getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index 6ececa2..71b8f3f 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -20,6 +20,9 @@
<p>The version of SQLite depends on the version of Android. See the following table:
<table style="width:auto;">
<tr><th>Android API</th><th>SQLite Version</th></tr>
+ <tr><td>API 34</td><td>3.39</td></tr>
+ <tr><td>API 33</td><td>3.32</td></tr>
+ <tr><td>API 32</td><td>3.32</td></tr>
<tr><td>API 31</td><td>3.32</td></tr>
<tr><td>API 30</td><td>3.28</td></tr>
<tr><td>API 28</td><td>3.22</td></tr>
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 48b5cac..d352be1 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3202,8 +3202,9 @@
* or if the camera device isn't a primary rear/front camera, the minimum required output
* stream configurations are the same as for applications targeting SDK version older than
* 31.</p>
- * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional mandatory
- * stream configurations on a per-capability basis.</p>
+ * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations }
+ * for additional mandatory stream configurations on a per-capability basis.</p>
* <p>*1: For JPEG format, the sizes may be restricted by below conditions:</p>
* <ul>
* <li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
@@ -3321,12 +3322,11 @@
* {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL }
* and {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES }.
* This is an app-readable conversion of the mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} based on
- * specific device level and capabilities.
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations guideline} based on specific device level and capabilities.
* Clients can use the array as a quick reference to find an appropriate camera stream
* combination.
* As per documentation, the stream combinations with given PREVIEW, RECORD and
@@ -3355,12 +3355,11 @@
/**
* <p>An array of mandatory concurrent stream combinations.
* This is an app-readable conversion of the concurrent mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * {@link android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
- * device which has its Id present in the set returned by
+ * {@link android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations guideline} for each device which has its Id present in the set returned by
* {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds }.
* Clients can use the array as a quick reference to find an appropriate camera stream
* combination.
@@ -3465,7 +3464,8 @@
* <p>If a camera device supports multi-resolution output streams for a particular format, for
* each of its mandatory stream combinations, the camera device will support using a
* MultiResolutionImageReader for the MAXIMUM stream of supported formats. Refer to
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional details.</p>
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs }
+ * for additional details.</p>
* <p>To use multi-resolution input streams, the supported formats can be queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputFormats }.
* A reprocessable CameraCaptureSession can then be created using an {@link android.hardware.camera2.params.InputConfiguration InputConfiguration} constructed with
* the input MultiResolutionStreamInfo group, queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputInfo }.</p>
@@ -3473,8 +3473,8 @@
* {@code YUV} output, or multi-resolution {@code PRIVATE} input and multi-resolution
* {@code PRIVATE} output, {@code JPEG} and {@code YUV} are guaranteed to be supported
* multi-resolution output stream formats. Refer to
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession } for
- * details about the additional mandatory stream combinations in this case.</p>
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs }}
+ * for details about the additional mandatory stream combinations in this case.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*/
@PublicKey
@@ -3586,12 +3586,11 @@
* {@link android.hardware.camera2.CaptureRequest } has {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} set
* to {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }.
* This is an app-readable conversion of the maximum resolution mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * {@link android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
- * device which has the
+ * {@link android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors guideline} for each device which has the
* {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR }
* capability.
* Clients can use the array as a quick reference to find an appropriate camera stream
@@ -3614,12 +3613,11 @@
* 10-bit output capability
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
* This is an app-readable conversion of the 10 bit output mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
- * device which has the
+ * {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations guideline} for each device which has the
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
* capability.
* Clients can use the array as a quick reference to find an appropriate camera stream
@@ -3639,12 +3637,12 @@
* <p>An array of mandatory stream combinations which are applicable when device lists
* {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.
* This is an app-readable conversion of the preview stabilization mandatory stream
- * combination {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * combination
+ * {@link android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
- * device which supports {@code PREVIEW_STABILIZATION}
+ * {@link android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations guideline} for each device which supports {@code PREVIEW_STABILIZATION}
* Clients can use the array as a quick reference to find an appropriate camera stream
* combination.
* The mandatory stream combination array will be {@code null} in case the device does not
@@ -3717,8 +3715,8 @@
* <p>The guaranteed stream combinations related to stream use case for a camera device with
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
* capability is documented in the camera device
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline}. The
- * application is strongly recommended to use one of the guaranteed stream combinations.
+ * {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline}. The application is strongly recommended to use one of the guaranteed stream
+ * combinations.
* If the application creates a session with a stream combination not in the guaranteed
* list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
* the camera device may ignore some stream use cases due to hardware constraints
@@ -3754,13 +3752,11 @@
/**
* <p>An array of mandatory stream combinations with stream use cases.
* This is an app-readable conversion of the mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables} with
- * each stream's use case being set.</p>
+ * {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations tables} with each stream's use case being set.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for a
- * camera device with
+ * {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline} for a camera device with
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
* capability.
* The mandatory stream combination array will be {@code null} in case the device doesn't
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ad68866..99b297a 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -636,8 +636,9 @@
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at
* least the following stream combinations:
*
+ * <h5>LEGACY-level guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">LEGACY-level guaranteed configurations</th></tr>
* <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
@@ -656,8 +657,9 @@
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
*
+ * <h5>LIMITED-level additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">LIMITED-level additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td colspan="2" id="rb"></td> <td>High-resolution video recording with preview.</td> </tr>
@@ -674,8 +676,9 @@
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
+ * <h5>FULL-level additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">FULL-level additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution GPU processing with preview.</td> </tr>
@@ -693,8 +696,9 @@
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
+ * <h5>RAW-capability additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">RAW-capability additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>No-preview DNG capture.</td> </tr>
@@ -716,8 +720,9 @@
* list for FULL-level devices, so this table is only relevant for LIMITED-level devices that
* support the BURST_CAPTURE capability.
*
+ * <h5>BURST-capability additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="5">BURST-capability additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution GPU processing with preview.</td> </tr>
@@ -733,8 +738,9 @@
* RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
*
+ * <h5>LEVEL-3 additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="11">LEVEL-3 additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>In-app viewfinder analysis with dynamic selection of output format.</td> </tr>
@@ -748,8 +754,9 @@
* <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed
* to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p>
*
+ * <h5>Concurrent stream guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code YUV}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
@@ -794,8 +801,9 @@
* stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
* MultiResolutionImageReader} created based on the variable max resolutions supported):
*
+ * <h5>LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</h5>
+ *
* <table>
- * <tr><th colspan="7">LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</th></tr>
* <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
@@ -814,8 +822,10 @@
*
* <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
* which clients can take advantage of : </p>
+ *
+ * <h5>Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</h5>
+ *
* <table>
- * <tr><th colspan="10">Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</th></tr>
* <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th> <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td colspan="3" id="rb"></td> <td>Ultra high res still image capture with preview</td> </tr>
@@ -834,8 +844,10 @@
* <p> 10-bit output capable
* {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
* devices support at least the following stream combinations: </p>
+ *
+ * <h5>10-bit output additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">10-bit output additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
@@ -887,8 +899,9 @@
* CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
* stream combinations:
*
+ * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="10">STREAM_USE_CASE capability additional guaranteed configurations</th></tr>
* <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
* <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple preview or in-app image processing</td> </tr>
@@ -911,8 +924,9 @@
* stream use-case in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES},
* support the additional stream combinations below:
*
+ * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
+ *
* <table>
- * <tr><th colspan="10">STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</th></tr>
* <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
* <tr> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Cropped RAW still capture without preview</td> </tr>
@@ -926,8 +940,10 @@
* the following stream combinations are guaranteed,
* for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
* {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p>
+ *
+ * <h5>Preview stabilization guaranteed stream configurations</h5>
+ *
* <table>
- * <tr><th colspan="7">Preview stabilization guaranteed stream configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td><td colspan="2" id="rb"></td> <td>Stabilized preview, GPU video processing, or no-preview stabilized video recording.</td> </tr>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4950373..dfc27ca 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1213,7 +1213,8 @@
* <ul>
* <li>Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 }</li>
* <li>All mandatory stream combinations for this specific capability as per
- * documentation {@link android.hardware.camera2.CameraDevice#createCaptureSession }</li>
+ * documentation
+ * {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations }</li>
* <li>In case the device is not able to capture some combination of supported
* standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
* then those constraints must be listed in
@@ -1252,9 +1253,10 @@
* </ul>
* <p>{@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES }
* lists all of the supported stream use cases.</p>
- * <p>Refer to {@link android.hardware.camera2.CameraDevice#createCaptureSession } for the
- * mandatory stream combinations involving stream use cases, which can also be queried
- * via {@link android.hardware.camera2.params.MandatoryStreamCombination }.</p>
+ * <p>Refer to
+ * {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations }
+ * for the mandatory stream combinations involving stream use cases, which can also be
+ * queried via {@link android.hardware.camera2.params.MandatoryStreamCombination }.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19;
@@ -1752,7 +1754,8 @@
* <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
* better.</p>
* <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+ * {@link android.hardware.camera2.CameraDevice#limited-level-additional-guaranteed-configurations }
+ * documentation are guaranteed to be supported.</p>
* <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
* support for color image capture. The only exception is that the device may
* alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
@@ -1779,7 +1782,8 @@
/**
* <p>This camera device is capable of supporting advanced imaging applications.</p>
* <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+ * {@link android.hardware.camera2.CameraDevice#full-level-additional-guaranteed-configurations }
+ * documentation are guaranteed to be supported.</p>
* <p>A <code>FULL</code> device will support below capabilities:</p>
* <ul>
* <li><code>BURST_CAPTURE</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
@@ -1807,7 +1811,9 @@
/**
* <p>This camera device is running in backward compatibility mode.</p>
- * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are supported.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the
+ * {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations }
+ * documentation are supported.</p>
* <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
* post-processing, arbitrary cropping regions, and has relaxed performance constraints.
* No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -1830,7 +1836,9 @@
* <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
* FULL-level capabilities.</p>
* <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
- * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+ * <code>LIMITED</code> tables in the
+ * {@link android.hardware.camera2.CameraDevice#level-3-additional-guaranteed-configurations }
+ * documentation are guaranteed to be supported.</p>
* <p>The following additional capabilities are guaranteed to be supported:</p>
* <ul>
* <li><code>YUV_REPROCESSING</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index ac7f2ca..7e42f43 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -179,7 +179,7 @@
* @return unmodifiable map between physical camera ids and their capture result metadata
*
* @deprecated
- * <p>Please use {@link #getPhysicalCameraTotalResults() instead to get the
+ * <p>Please use {@link #getPhysicalCameraTotalResults()} instead to get the
* physical cameras' {@code TotalCaptureResult}.</p>
*/
public Map<String, CaptureResult> getPhysicalCameraResults() {
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index d87226c..65d4b43 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -77,18 +77,18 @@
private static final String TAG = "CameraAdvancedExtensionSessionImpl";
private final Executor mExecutor;
- private final CameraDevice mCameraDevice;
+ private CameraDevice mCameraDevice;
private final Map<String, CameraMetadataNative> mCharacteristicsMap;
private final long mExtensionClientId;
private final Handler mHandler;
private final HandlerThread mHandlerThread;
private final CameraExtensionSession.StateCallback mCallbacks;
- private final IAdvancedExtenderImpl mAdvancedExtender;
+ private IAdvancedExtenderImpl mAdvancedExtender;
// maps registered camera surfaces to extension output configs
private final HashMap<Surface, CameraOutputConfig> mCameraConfigMap = new HashMap<>();
// maps camera extension output ids to camera registered image readers
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
- private final RequestProcessor mRequestProcessor = new RequestProcessor();
+ private RequestProcessor mRequestProcessor = new RequestProcessor();
private final int mSessionId;
private Surface mClientRepeatingRequestSurface;
@@ -100,7 +100,7 @@
private final ExtensionSessionStatsAggregator mStatsAggregator;
private boolean mInitialized;
-
+ private boolean mSessionClosed;
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -237,6 +237,7 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mInitialized = false;
+ mSessionClosed = false;
mInitializeHandler = new InitializeSessionHandler();
mSessionId = sessionId;
mInterfaceLock = cameraDevice.mInterfaceLock;
@@ -424,7 +425,7 @@
mSessionProcessor.setParameters(request);
seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
- executor, listener));
+ executor, listener, mCameraDevice.getId()));
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
"Failed to enable repeating request, extension service failed to respond!");
@@ -452,7 +453,7 @@
mSessionProcessor.setParameters(request);
seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
- executor, listener), isPostviewRequested);
+ executor, listener, mCameraDevice.getId()), isPostviewRequested);
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
" to submit capture request, extension service failed to respond!");
@@ -460,8 +461,8 @@
} else if ((mClientRepeatingRequestSurface != null) &&
request.containsTarget(mClientRepeatingRequestSurface)) {
try {
- seqId = mSessionProcessor.startTrigger(request,
- new RequestCallbackHandler(request, executor, listener));
+ seqId = mSessionProcessor.startTrigger(request, new RequestCallbackHandler(
+ request, executor, listener, mCameraDevice.getId()));
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
" to submit trigger request, extension service failed to respond!");
@@ -528,6 +529,7 @@
mCaptureSession.stopRepeating();
mSessionProcessor.stopRepeating();
mSessionProcessor.onCaptureSessionEnd();
+ mSessionClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to stop the repeating request or end the session,"
+ " , extension service does not respond!") ;
@@ -560,6 +562,9 @@
if (mSessionProcessor != null) {
try {
+ if (!mSessionClosed) {
+ mSessionProcessor.onCaptureSessionEnd();
+ }
mSessionProcessor.deInitSession();
} catch (RemoteException e) {
Log.e(TAG, "Failed to de-initialize session processor, extension service"
@@ -584,6 +589,10 @@
mClientRepeatingRequestSurface = null;
mClientCaptureSurface = null;
+ mCaptureSession = null;
+ mRequestProcessor = null;
+ mCameraDevice = null;
+ mAdvancedExtender = null;
}
if (notifyClose && !skipCloseNotification) {
@@ -706,13 +715,16 @@
private final CaptureRequest mClientRequest;
private final Executor mClientExecutor;
private final ExtensionCaptureCallback mClientCallbacks;
+ private final String mCameraId;
private RequestCallbackHandler(@NonNull CaptureRequest clientRequest,
@NonNull Executor clientExecutor,
- @NonNull ExtensionCaptureCallback clientCallbacks) {
+ @NonNull ExtensionCaptureCallback clientCallbacks,
+ @NonNull String cameraId) {
mClientRequest = clientRequest;
mClientExecutor = clientExecutor;
mClientCallbacks = clientCallbacks;
+ mCameraId = cameraId;
}
@Override
@@ -784,7 +796,7 @@
}
result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
- TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result,
+ TotalCaptureResult totalResult = new TotalCaptureResult(mCameraId, result,
mClientRequest, requestId, timestamp, new ArrayList<>(), mSessionId,
new PhysicalCaptureResultInfo[0]);
final long ident = Binder.clearCallingIdentity();
@@ -1036,14 +1048,20 @@
public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1;
try {
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
- for (Request request : requests) {
- captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
- mCameraConfigMap));
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return seqId;
+ }
+
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+ for (Request request : requests) {
+ captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+ mCameraConfigMap));
+ }
+ seqId = mCaptureSession.captureBurstRequests(captureRequests,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
}
- seqId = mCaptureSession.captureBurstRequests(captureRequests,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to submit capture requests!");
} catch (IllegalStateException e) {
@@ -1057,11 +1075,17 @@
public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1;
try {
- CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return seqId;
+ }
+
+ CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
request, mCameraConfigMap);
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to enable repeating request!");
} catch (IllegalStateException e) {
@@ -1074,7 +1098,13 @@
@Override
public void abortCaptures() {
try {
- mCaptureSession.abortCaptures();
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return;
+ }
+
+ mCaptureSession.abortCaptures();
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed during capture abort!");
} catch (IllegalStateException e) {
@@ -1085,7 +1115,13 @@
@Override
public void stopRepeating() {
try {
- mCaptureSession.stopRepeating();
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return;
+ }
+
+ mCaptureSession.stopRepeating();
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed during repeating capture stop!");
} catch (IllegalStateException e) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 01977f6..6195443 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -103,6 +103,7 @@
private static final int MSG_UDFPS_POINTER_DOWN = 108;
private static final int MSG_UDFPS_POINTER_UP = 109;
private static final int MSG_POWER_BUTTON_PRESSED = 110;
+ private static final int MSG_UDFPS_OVERLAY_SHOWN = 111;
/**
* @hide
@@ -121,6 +122,24 @@
public @interface EnrollReason {}
/**
+ * Udfps ui event of overlay is shown on the screen.
+ * @hide
+ */
+ public static final int UDFPS_UI_OVERLAY_SHOWN = 1;
+ /**
+ * Udfps ui event of the udfps UI being ready (e.g. HBM illumination is enabled).
+ * @hide
+ */
+ public static final int UDFPS_UI_READY = 2;
+
+ /**
+ * @hide
+ */
+ @IntDef({UDFPS_UI_OVERLAY_SHOWN, UDFPS_UI_READY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UdfpsUiEvent{}
+
+ /**
* Request authentication with any single sensor.
* @hide
*/
@@ -475,12 +494,17 @@
/**
* Called when a pointer down event has occurred.
*/
- public void onPointerDown(int sensorId){ }
+ public void onUdfpsPointerDown(int sensorId){ }
/**
* Called when a pointer up event has occurred.
*/
- public void onPointerUp(int sensorId){ }
+ public void onUdfpsPointerUp(int sensorId){ }
+
+ /**
+ * Called when udfps overlay is shown.
+ */
+ public void onUdfpsOverlayShown() { }
}
/**
@@ -1112,14 +1136,14 @@
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onUiReady(long requestId, int sensorId) {
+ public void onUdfpsUiEvent(@UdfpsUiEvent int event, long requestId, int sensorId) {
if (mService == null) {
- Slog.w(TAG, "onUiReady: no fingerprint service");
+ Slog.w(TAG, "onUdfpsUiEvent: no fingerprint service");
return;
}
try {
- mService.onUiReady(requestId, sensorId);
+ mService.onUdfpsUiEvent(event, requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1365,6 +1389,8 @@
case MSG_POWER_BUTTON_PRESSED:
sendPowerPressed();
break;
+ case MSG_UDFPS_OVERLAY_SHOWN:
+ sendUdfpsOverlayShown();
default:
Slog.w(TAG, "Unknown message: " + msg.what);
@@ -1489,7 +1515,7 @@
}
if (mEnrollmentCallback != null) {
- mEnrollmentCallback.onPointerDown(sensorId);
+ mEnrollmentCallback.onUdfpsPointerDown(sensorId);
}
}
@@ -1500,7 +1526,7 @@
mAuthenticationCallback.onUdfpsPointerUp(sensorId);
}
if (mEnrollmentCallback != null) {
- mEnrollmentCallback.onPointerUp(sensorId);
+ mEnrollmentCallback.onUdfpsPointerUp(sensorId);
}
}
@@ -1512,6 +1538,12 @@
}
}
+ private void sendUdfpsOverlayShown() {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onUdfpsOverlayShown();
+ }
+ }
+
/**
* @hide
*/
@@ -1787,6 +1819,11 @@
public void onUdfpsPointerUp(int sensorId) {
mHandler.obtainMessage(MSG_UDFPS_POINTER_UP, sensorId, 0).sendToTarget();
}
+
+ @Override
+ public void onUdfpsOverlayShown() {
+ mHandler.obtainMessage(MSG_UDFPS_OVERLAY_SHOWN).sendToTarget();
+ }
};
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java b/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
index a9779b5..89d710d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
+++ b/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
@@ -75,4 +75,9 @@
public void onUdfpsPointerUp(int sensorId) throws RemoteException {
}
+
+ @Override
+ public void onUdfpsOverlayShown() throws RemoteException {
+
+ }
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index ec5749e..ff2f313 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -193,7 +193,7 @@
// Notifies about the fingerprint UI being ready (e.g. HBM illumination is enabled).
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
- void onUiReady(long requestId, int sensorId);
+ void onUdfpsUiEvent(int event, long requestId, int sensorId);
// Sets the controller for managing the UDFPS overlay.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index 9cea1fe..91a32d7 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -32,4 +32,5 @@
void onChallengeGenerated(int sensorId, int userId, long challenge);
void onUdfpsPointerDown(int sensorId);
void onUdfpsPointerUp(int sensorId);
+ void onUdfpsOverlayShown();
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a9c4818..2f9c207 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -52,8 +52,6 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
@@ -160,6 +158,7 @@
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.RingBuffer;
import org.xmlpull.v1.XmlPullParserException;
@@ -482,43 +481,53 @@
public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
/**
- * Enum flag to be used for {@link #setBackDisposition(int)}.
+ * Enum values to be used for {@link #setBackDisposition(int)}.
*
* @hide
*/
- @Retention(SOURCE)
- @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
- BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
- prefix = "BACK_DISPOSITION_")
+ @IntDef(prefix = { "BACK_DISPOSITION_" }, value = {
+ BACK_DISPOSITION_DEFAULT,
+ BACK_DISPOSITION_WILL_NOT_DISMISS,
+ BACK_DISPOSITION_WILL_DISMISS,
+ BACK_DISPOSITION_ADJUST_NOTHING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
public @interface BackDispositionMode {}
/**
+ * Enum flags to be used for {@link #setImeWindowStatus}, representing the current state of the
+ * IME window visibility.
+ *
* @hide
+ */
+ @IntDef(flag = true, prefix = { "IME_" }, value = {
+ IME_ACTIVE,
+ IME_VISIBLE,
+ IME_VISIBLE_IMPERCEPTIBLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImeWindowVisibility {}
+
+ /**
* The IME is active. It may or may not be visible.
+ * @hide
*/
public static final int IME_ACTIVE = 0x1;
/**
- * @hide
* The IME is perceptibly visible to the user.
+ * @hide
*/
public static final int IME_VISIBLE = 0x2;
/**
- * @hide
- * The IME is active and ready with views but set invisible.
- * This flag cannot be combined with {@link #IME_VISIBLE}.
- */
- public static final int IME_INVISIBLE = 0x4;
-
- /**
- * @hide
* The IME is visible, but not yet perceptible to the user (e.g. fading in)
* by {@link android.view.WindowInsetsController}.
*
* @see InputMethodManager#reportPerceptible
+ * @hide
*/
- public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x8;
+ public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x4;
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
@@ -631,9 +640,18 @@
int mStatusIcon;
+ /**
+ * Latest value reported of back disposition mode.
+ */
@BackDispositionMode
int mBackDisposition;
+ /**
+ * Latest value reported of IME window visibility flags.
+ */
+ @ImeWindowVisibility
+ private int mImeWindowVisibility;
+
private Object mLock = new Object();
@GuardedBy("mLock")
private boolean mNotifyUserActionSent;
@@ -1210,8 +1228,14 @@
mImeSurfaceRemoverRunnable = null;
}
- private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
- mPrivOps.setImeWindowStatusAsync(visibilityFlags, backDisposition);
+ private void setImeWindowStatus(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition) {
+ if (vis == mImeWindowVisibility && backDisposition == mBackDisposition) {
+ return;
+ }
+ mImeWindowVisibility = Preconditions.checkFlagsArgument(vis, IME_ACTIVE | IME_VISIBLE);
+ mBackDisposition = backDisposition;
+ mPrivOps.setImeWindowStatusAsync(mImeWindowVisibility, mBackDisposition);
}
/** Set region of the keyboard to be avoided from back gesture */
@@ -1885,15 +1909,11 @@
* @param disposition disposition mode to be set
*/
public void setBackDisposition(@BackDispositionMode int disposition) {
- if (disposition == mBackDisposition) {
- return;
- }
- if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
+ if (disposition < BACK_DISPOSITION_MIN || disposition > BACK_DISPOSITION_MAX) {
Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
return;
}
- mBackDisposition = disposition;
- setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+ setImeWindowStatus(mImeWindowVisibility, disposition);
}
/**
@@ -2867,14 +2887,8 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
- final int previousImeWindowStatus =
- (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
- ? (!mWindowVisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
startViews(prepareWindow(showInput));
- final int nextImeWindowStatus = mapToImeWindowStatus();
- if (previousImeWindowStatus != nextImeWindowStatus) {
- setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
- }
+ setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
mNavigationBarController.onWindowShown();
// compute visibility
@@ -4085,9 +4099,9 @@
};
}
+ @ImeWindowVisibility
private int mapToImeWindowStatus() {
- return IME_ACTIVE
- | (isInputViewShown() ? IME_VISIBLE : 0);
+ return IME_ACTIVE | (mDecorViewVisible ? IME_VISIBLE : 0);
}
private boolean isAutomotive() {
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index cacde7f..9e97216 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -711,6 +711,7 @@
/* Stale sService pointer */
if (sIsInitialized) sIsInitialized = false;
}
+ return null;
}
/* Try to initialize the service */
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 2bad670..5072876 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1966,7 +1966,7 @@
// Values for NUM_GPS_SIGNAL_QUALITY_LEVELS
public static final int STATE2_GPS_SIGNAL_QUALITY_SHIFT = 7;
public static final int STATE2_GPS_SIGNAL_QUALITY_MASK =
- 0x1 << STATE2_GPS_SIGNAL_QUALITY_SHIFT;
+ 0x3 << STATE2_GPS_SIGNAL_QUALITY_SHIFT;
public static final int STATE2_POWER_SAVE_FLAG = 1<<31;
public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
@@ -3028,7 +3028,7 @@
"cellular_high_tx_power", "Chtp"),
new BitDescription(HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK,
HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT, "gps_signal_quality", "Gss",
- new String[] { "poor", "good"}, new String[] { "poor", "good"})
+ new String[] { "poor", "good", "none"}, new String[] { "poor", "good", "none"})
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 94971b8..c9073fa 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -123,6 +123,7 @@
private int mAngleOptInIndex = -1;
private boolean mEnabledByGameMode = false;
+ private boolean mShouldUseAngle = false;
/**
* Set up GraphicsEnvironment
@@ -141,19 +142,16 @@
// Setup ANGLE and pass down ANGLE details to the C++ code
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
- boolean useAngle = false;
if (setupAngle(context, coreSettings, pm, packageName)) {
- if (shouldUseAngle(context, coreSettings, packageName)) {
- useAngle = true;
- setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
- 0, packageName, getVulkanVersion(pm));
- }
+ mShouldUseAngle = true;
+ setGpuStats(ANGLE_DRIVER_NAME, ANGLE_DRIVER_VERSION_NAME, ANGLE_DRIVER_VERSION_CODE,
+ 0, packageName, getVulkanVersion(pm));
}
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
if (!chooseDriver(context, coreSettings, pm, packageName, appInfoWithMetaData)) {
- if (!useAngle) {
+ if (!mShouldUseAngle) {
setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME,
SYSTEM_DRIVER_VERSION_CODE,
SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0),
@@ -636,44 +634,35 @@
}
/**
- * Determine if ANGLE will be used and setup the environment
- */
- private boolean setupAndUseAngle(Context context, String packageName) {
- // Need to make sure we are evaluating ANGLE usage for the correct circumstances
- if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
- Log.v(TAG, "Package '" + packageName + "' should not use ANGLE");
- return false;
- }
-
- final boolean useAngle = getShouldUseAngle(packageName);
- Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
-
- return useAngle;
- }
-
- /**
- * Show the ANGLE in Use Dialog Box
+ * Show the ANGLE in use dialog box.
+ * The ANGLE in use dialog box will show up as long as the application
+ * should use ANGLE. It does not mean the application has successfully
+ * loaded ANGLE because this check happens before the loading completes.
* @param context
*/
public void showAngleInUseDialogBox(Context context) {
- final String packageName = context.getPackageName();
-
- if (shouldShowAngleInUseDialogBox(context) && setupAndUseAngle(context, packageName)) {
- final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE);
- String anglePkg = getAnglePackageName(context.getPackageManager());
- intent.setPackage(anglePkg);
-
- context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Bundle results = getResultExtras(true);
-
- String toastMsg = results.getString(INTENT_KEY_A4A_TOAST_MESSAGE);
- final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
- toast.show();
- }
- }, null, Activity.RESULT_OK, null, null);
+ if (!shouldShowAngleInUseDialogBox(context)) {
+ return;
}
+
+ if (!mShouldUseAngle) {
+ return;
+ }
+
+ final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE);
+ final String anglePkg = getAnglePackageName(context.getPackageManager());
+ intent.setPackage(anglePkg);
+
+ context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Bundle results = getResultExtras(true);
+
+ final String toastMsg = results.getString(INTENT_KEY_A4A_TOAST_MESSAGE);
+ final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
+ toast.show();
+ }
+ }, null, Activity.RESULT_OK, null, null);
}
private String[] getAngleEglFeatures(Context context, Bundle coreSettings) {
@@ -901,9 +890,8 @@
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
- private static native void setAngleInfo(String path, String appPackage,
+ private static native void setAngleInfo(String path, String packageName,
String devOptIn, String[] features);
- private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
private static native void nativeToggleAngleAsSystemDriver(boolean enabled);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0144d22..84dc79b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1770,10 +1770,19 @@
/**
* Specifies if a user is not allowed to use 2g networks.
*
+ * <p> This is a security feature. 2g has no mutual authentication between a device and
+ * cellular base station and downgrading a device's connection to 2g is a common tactic for
+ * several types of privacy and security compromising attacks that could allow an adversary
+ * to intercept, inject, or modify cellular communications.
+ *
* <p>This restriction can only be set by a device owner or a profile owner of an
* organization-owned managed profile on the parent profile.
- * In all cases, the setting applies globally on the device and will prevent the device from
- * scanning for or connecting to 2g networks, except in the case of an emergency.
+ * In all cases, the setting applies globally on the device.
+ *
+ * <p> Cellular connectivity loss (where a device would have otherwise successfully
+ * connected to a 2g network) occurs if the device is in an area where only 2g networks are
+ * available. Emergency calls are an exception and are never impacted. The device will still
+ * scan for and connect to a 2g network for emergency calls.
*
* <p>Holders of the permission
* {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_MOBILE_NETWORK}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 319a0ea..84a197a 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -40,6 +40,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
@@ -81,8 +82,8 @@
public final class PermissionControllerManager {
private static final String TAG = PermissionControllerManager.class.getSimpleName();
- private static final long REQUEST_TIMEOUT_MILLIS = 60000;
- private static final long UNBIND_TIMEOUT_MILLIS = 10000;
+ private static final long REQUEST_TIMEOUT_MILLIS = 60000L * Build.HW_TIMEOUT_MULTIPLIER;
+ private static final long UNBIND_TIMEOUT_MILLIS = 10000L * Build.HW_TIMEOUT_MULTIPLIER;
private static final int CHUNK_SIZE = 4 * 1024;
private static final Object sLock = new Object();
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index e256ea0..9ae87de 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -75,6 +75,7 @@
import com.android.internal.R;
import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
+import com.android.modules.utils.build.SdkLevel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -181,7 +182,7 @@
*
* @hide
*/
- public static final boolean USE_ACCESS_CHECKING_SERVICE = false;
+ public static final boolean USE_ACCESS_CHECKING_SERVICE = SdkLevel.isAtLeastV();
/**
* The time to wait in between refreshing the exempted indicator role packages
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7edfe7c..fd28446 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16744,6 +16744,30 @@
public static final String AWARE_ALLOWED = "aware_allowed";
/**
+ * Overrides internal R.integer.config_shortPressOnPowerBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String POWER_BUTTON_SHORT_PRESS = "power_button_short_press";
+
+ /**
+ * Overrides internal R.integer.config_doublePressOnPowerBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String POWER_BUTTON_DOUBLE_PRESS = "power_button_double_press";
+
+ /**
+ * Overrides internal R.integer.config_triplePressOnPowerBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String POWER_BUTTON_TRIPLE_PRESS = "power_button_triple_press";
+
+ /**
* Overrides internal R.integer.config_longPressOnPowerBehavior.
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
* Used by PhoneWindowManager.
@@ -16774,6 +16798,42 @@
"power_button_very_long_press";
/**
+ * Overrides internal R.integer.config_shortPressOnStemPrimaryBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String STEM_PRIMARY_BUTTON_SHORT_PRESS =
+ "stem_primary_button_short_press";
+
+ /**
+ * Overrides internal R.integer.config_doublePressOnStemPrimaryBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String STEM_PRIMARY_BUTTON_DOUBLE_PRESS =
+ "stem_primary_button_double_press";
+
+ /**
+ * Overrides internal R.integer.config_triplePressOnStemPrimaryBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String STEM_PRIMARY_BUTTON_TRIPLE_PRESS =
+ "stem_primary_button_triple_press";
+
+ /**
+ * Overrides internal R.integer.config_longPressOnStemPrimaryBehavior.
+ * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
+ * Used by PhoneWindowManager.
+ * @hide
+ */
+ public static final String STEM_PRIMARY_BUTTON_LONG_PRESS =
+ "stem_primary_button_long_press";
+
+ /**
* Overrides internal R.integer.config_keyChordPowerVolumeUp.
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
* Used by PhoneWindowManager.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 4e086c2..dbc1be1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -44,6 +44,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
@@ -190,6 +191,9 @@
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ // TODO (b/287037772) remove this flag and the forceReport argument in reportVisibility
+ private boolean mIsWearOs;
+
static final class WallpaperCommand {
String action;
int x;
@@ -2282,7 +2286,8 @@
@Override
public void onDisplayChanged(int displayId) {
if (mDisplay.getDisplayId() == displayId) {
- boolean forceReport = mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
+ boolean forceReport = mIsWearOs
+ && mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
reportVisibility(forceReport);
}
}
@@ -2734,6 +2739,7 @@
mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ mIsWearOs = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
super.onCreate();
Trace.endSection();
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 434b1c7..e2c5539 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -490,13 +490,16 @@
/**
* Notify changes to activity state changes on certain subscription.
*
+ * @param slotIndex for which data activity changed. Can be derived from subId except
+ * when subId is invalid.
* @param subId for which data activity state changed.
* @param dataActivityType indicates the latest data activity type e.g, {@link
* TelephonyManager#DATA_ACTIVITY_IN}
*/
- public void notifyDataActivityChanged(int subId, @DataActivityType int dataActivityType) {
+ public void notifyDataActivityChanged(int slotIndex, int subId,
+ @DataActivityType int dataActivityType) {
try {
- sRegistry.notifyDataActivityForSubscriber(subId, dataActivityType);
+ sRegistry.notifyDataActivityForSubscriber(slotIndex, subId, dataActivityType);
} catch (RemoteException ex) {
// system process is dead
throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index e811390..9969d29 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -106,7 +106,7 @@
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
+ Log.w("URLSpan", "Activity was not found for intent, " + intent.toString());
}
}
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index dc06671..1ed5d3f 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -23,6 +23,9 @@
import android.hardware.HardwareBuffer;
import android.window.SurfaceSyncGroup;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
/**
* Provides an interface to the root-Surface of a View Hierarchy or Window. This
* is used in combination with the {@link android.view.SurfaceControl} API to enable
@@ -167,4 +170,40 @@
*/
default void setChildBoundingInsets(@NonNull Rect insets) {
}
+
+ /**
+ * Add a trusted presentation listener on the SurfaceControl associated with this window.
+ *
+ * @param t Transaction that the trusted presentation listener is added on. This should
+ * be applied by the caller.
+ * @param thresholds The {@link SurfaceControl.TrustedPresentationThresholds} that will specify
+ * when the to invoke the callback.
+ * @param executor The {@link Executor} where the callback will be invoked on.
+ * @param listener The {@link Consumer} that will receive the callbacks when entered or
+ * exited the threshold.
+ *
+ * @see SurfaceControl.Transaction#setTrustedPresentationCallback(SurfaceControl,
+ * SurfaceControl.TrustedPresentationThresholds, Executor, Consumer)
+ *
+ * @hide b/287076178 un-hide with API bump
+ */
+ default void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.TrustedPresentationThresholds thresholds,
+ @NonNull Executor executor, @NonNull Consumer<Boolean> listener) {
+ }
+
+ /**
+ * Remove a trusted presentation listener on the SurfaceControl associated with this window.
+ *
+ * @param t Transaction that the trusted presentation listener removed on. This should
+ * be applied by the caller.
+ * @param listener The {@link Consumer} that was previously registered with
+ * addTrustedPresentationCallback that should be removed.
+ *
+ * @see SurfaceControl.Transaction#clearTrustedPresentationCallback(SurfaceControl)
+ * @hide b/287076178 un-hide with API bump
+ */
+ default void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull Consumer<Boolean> listener) {
+ }
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index ca3dff3..d80001d 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -732,12 +732,23 @@
* @throws IllegalStateException if no frame is in progress.
* @hide
*/
- @TestApi
- @UnsupportedAppUsage
public long getExpectedPresentationTimeNanos() {
return mFrameData.getPreferredFrameTimeline().getExpectedPresentationTimeNanos();
}
+
+ /**
+ * Same as {@link #getExpectedPresentationTimeNanos()} but with millisecond precision.
+ *
+ * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
+ *
+ * @throws IllegalStateException if no frame is in progress.
+ * @hide
+ */
+ public long getExpectedPresentationTimeMillis() {
+ return getExpectedPresentationTimeNanos() / TimeUtils.NANOS_PER_MS;
+ }
+
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 50246f6..a46136a 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -158,7 +158,11 @@
static final int FRAME_TIMELINES_CAPACITY = 7;
public static class FrameTimeline {
- FrameTimeline() {}
+ FrameTimeline() {
+ // Some reasonable values (+10 ms) for default timestamps.
+ deadline = System.nanoTime() + 10_000_000;
+ expectedPresentationTime = deadline + 10_000_000;
+ }
// Called from native code.
@SuppressWarnings("unused")
@@ -179,11 +183,11 @@
public long vsyncId = FrameInfo.INVALID_VSYNC_ID;
// The frame timestamp for when the frame is expected to be presented.
- public long expectedPresentationTime = Long.MAX_VALUE;
+ public long expectedPresentationTime;
// The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
// allotted for the frame to be completed.
- public long deadline = Long.MAX_VALUE;
+ public long deadline;
}
/**
@@ -197,7 +201,9 @@
public int preferredFrameTimelineIndex = 0;
- public int frameTimelinesLength = 0;
+ // The default FrameTimeline is a placeholder populated with invalid vsync ID and some
+ // reasonable timestamps.
+ public int frameTimelinesLength = 1;
VsyncEventData() {
frameTimelines = new FrameTimeline[FRAME_TIMELINES_CAPACITY];
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index ab58306b..c501f5a 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -132,12 +132,7 @@
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
mState = null;
- final int actionIndex = motionEvent.getActionIndex();
- final int toolType = motionEvent.getToolType(actionIndex);
- // TOOL_TYPE_ERASER is also from stylus. This indicates that the user is holding
- // the eraser button during handwriting.
- if (toolType != MotionEvent.TOOL_TYPE_STYLUS
- && toolType != MotionEvent.TOOL_TYPE_ERASER) {
+ if (!motionEvent.isStylusPointer()) {
// The motion event is not from a stylus event, ignore it.
return false;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 61a7277..dceae90 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -178,7 +178,8 @@
if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
compatInsetsTypes &= ~statusBars();
}
- if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
+ if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)
+ && !alwaysConsumeSystemBars) {
compatInsetsTypes = 0;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d0ab8a7..71e9052 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22467,6 +22467,22 @@
}
/**
+ * Configure the {@link android.graphics.RenderEffect} to apply to the backdrop contents of this
+ * View. This will apply a visual effect to the result of the backdrop contents of this View
+ * before it is drawn. For example if
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)}
+ * is provided, the previous content behind this View will be blurred before this View is drawn.
+ * @param renderEffect to be applied to the View. Passing null clears the previously configured
+ * {@link RenderEffect}
+ * @hide
+ */
+ public void setBackdropRenderEffect(@Nullable RenderEffect renderEffect) {
+ if (mRenderNode.setBackdropRenderEffect(renderEffect)) {
+ invalidateViewProperty(true, true);
+ }
+ }
+
+ /**
* Updates the {@link Paint} object used with the current layer (used only if the current
* layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
* provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f21851f..ae6a804 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11593,4 +11593,17 @@
mChildBoundingInsetsChanged = true;
scheduleTraversals();
}
+
+ @Override
+ public void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.TrustedPresentationThresholds thresholds,
+ @NonNull Executor executor, @NonNull Consumer<Boolean> listener) {
+ t.setTrustedPresentationCallback(getSurfaceControl(), thresholds, executor, listener);
+ }
+
+ @Override
+ public void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull Consumer<Boolean> listener) {
+ t.clearTrustedPresentationCallback(getSurfaceControl());
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 75eb00a..73477ec 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -459,12 +459,16 @@
/**
* Represents the event of clicking on a {@link android.view.View} like
* {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
+ * <p>See {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_CLICK} for more
+ * details.
*/
public static final int TYPE_VIEW_CLICKED = 1 /* << 0 */;;
/**
* Represents the event of long clicking on a {@link android.view.View} like
* {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
+ * <p>See {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_LONG_CLICK} for more
+ * details.
*/
public static final int TYPE_VIEW_LONG_CLICKED = 1 << 1;
@@ -591,6 +595,8 @@
/**
* Represents the event of a context click on a {@link android.view.View}.
+ * <p>See {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_CONTEXT_CLICK} for more
+ * details.
*/
public static final int TYPE_VIEW_CONTEXT_CLICKED = 1 << 23;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 11b0d5f..b220c4d 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -848,7 +848,7 @@
List<AccessibilityServiceInfo> services = null;
try {
- services = service.getInstalledAccessibilityServiceList(userId);
+ services = service.getInstalledAccessibilityServiceList(userId).getList();
if (DEBUG) {
Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 7199f60..12a5a7f 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -290,6 +290,7 @@
/**
* Action that selects the node.
+ * @see AccessibilityAction#ACTION_SELECT
*/
public static final int ACTION_SELECT = 1 << 2;
@@ -301,7 +302,7 @@
/**
* Action that clicks on the node info.
*
- * See {@link AccessibilityAction#ACTION_CLICK}
+ * @see AccessibilityAction#ACTION_CLICK
*/
public static final int ACTION_CLICK = 1 << 4;
@@ -309,6 +310,7 @@
* Action that long clicks on the node.
*
* <p>It does not support coordinate information for anchoring.</p>
+ * @see AccessibilityAction#ACTION_LONG_CLICK
*/
public static final int ACTION_LONG_CLICK = 1 << 5;
@@ -445,19 +447,8 @@
/**
* Action to set the selection. Performing this action with no arguments
* clears the selection.
- * <p>
- * <strong>Arguments:</strong>
- * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
- * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
- * <strong>Example:</strong>
- * <code><pre><p>
- * Bundle arguments = new Bundle();
- * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
- * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
- * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
- * </code></pre></p>
- * </p>
*
+ * @see AccessibilityAction#ACTION_SET_SELECTION
* @see #ACTION_ARGUMENT_SELECTION_START_INT
* @see #ACTION_ARGUMENT_SELECTION_END_INT
*/
@@ -482,16 +473,7 @@
* Action that sets the text of the node. Performing the action without argument, using <code>
* null</code> or empty {@link CharSequence} will clear the text. This action will also put the
* cursor at the end of text.
- * <p>
- * <strong>Arguments:</strong>
- * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
- * <strong>Example:</strong>
- * <code><pre><p>
- * Bundle arguments = new Bundle();
- * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
- * "android");
- * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
- * </code></pre></p>
+ * @see AccessibilityAction#ACTION_SET_TEXT
*/
public static final int ACTION_SET_TEXT = 1 << 21;
@@ -5144,7 +5126,7 @@
* and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
* example, an application may define a custom action for clearing the user history.
* </li>
- * <li><strong>Overriden standard actions</strong> - These are actions that override
+ * <li><strong>Overridden standard actions</strong> - These are actions that override
* standard actions to customize them. For example, an app may add a label to the
* standard {@link #ACTION_CLICK} action to indicate to the user that this action clears
* browsing history.
@@ -5187,24 +5169,45 @@
/**
* Action that selects the node.
+ * The view the implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SELECTED} event.
+ * @see AccessibilityAction#ACTION_CLEAR_SELECTION
*/
public static final AccessibilityAction ACTION_SELECT =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_SELECT);
/**
* Action that deselects the node.
+ * @see AccessibilityAction#ACTION_SELECT
*/
public static final AccessibilityAction ACTION_CLEAR_SELECTION =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
/**
* Action that clicks on the node info.
+ *
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} event. In the View system,
+ * the default handling of this action when performed by a service is to call
+ * {@link View#performClick()}, and setting a
+ * {@link View#setOnClickListener(View.OnClickListener)} automatically adds this action.
+ *
+ * <p>{@link #isClickable()} should return true if this action is available.
*/
public static final AccessibilityAction ACTION_CLICK =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK);
/**
* Action that long clicks on the node.
+ *
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED} event. In the View system,
+ * the default handling of this action when performed by a service is to call
+ * {@link View#performLongClick()}, and setting a
+ * {@link View#setOnLongClickListener(View.OnLongClickListener)} automatically adds this
+ * action.
+ *
+ * <p>{@link #isLongClickable()} should return true if this action is available.
*/
public static final AccessibilityAction ACTION_LONG_CLICK =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
@@ -5409,7 +5412,10 @@
* info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
* </code></pre></p>
* </p>
- *
+ * <p> If this is a text selection, the UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED} event if its selection is
+ * updated. This element should also return {@code true} for
+ * {@link AccessibilityNodeInfo#isTextSelectable()}.
* @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
* AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
* @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
@@ -5451,6 +5457,10 @@
* "android");
* info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
* </code></pre></p>
+ * <p> The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} event if its text is updated.
+ * This element should also return {@code true} for
+ * {@link AccessibilityNodeInfo#isEditable()}.
*/
public static final AccessibilityAction ACTION_SET_TEXT =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT);
@@ -5571,6 +5581,18 @@
/**
* Action that context clicks the node.
+ *
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_CONTEXT_CLICKED} event. In the View system,
+ * the default handling of this action when performed by a service is to call
+ * {@link View#performContextClick()}, and setting a
+ * {@link View#setOnContextClickListener(View.OnContextClickListener)} automatically adds
+ * this action.
+ *
+ * <p>A context click usually occurs from a mouse pointer right-click or a stylus button
+ * press.
+ *
+ * <p>{@link #isContextClickable()} should return true if this action is available.
*/
public static final AccessibilityAction ACTION_CONTEXT_CLICK =
new AccessibilityAction(R.id.accessibilityActionContextClick);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 390503b..7a1112f 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -21,6 +21,7 @@
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
+import android.content.pm.ParceledListSlice;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -47,7 +48,7 @@
boolean removeClient(IAccessibilityManagerClient client, int userId);
- List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
+ ParceledListSlice<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 40b060a..3f308e6 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2657,17 +2657,6 @@
}
}
- if (windowGainingFocus == null) {
- windowGainingFocus = view.getWindowToken();
- if (windowGainingFocus == null) {
- Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
- return false;
- }
- startInputFlags = getStartInputFlags(view, startInputFlags);
- softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
- windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
- }
-
// Now we need to get an input connection from the served view.
// This is complicated in a couple ways: we can't be holding our lock
// when calling out to the view, and we need to make sure we call into
@@ -2690,6 +2679,17 @@
return false;
}
+ if (windowGainingFocus == null) {
+ windowGainingFocus = view.getWindowToken();
+ if (windowGainingFocus == null) {
+ Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
+ return false;
+ }
+ startInputFlags = getStartInputFlags(view, startInputFlags);
+ softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
+ windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
+ }
+
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index fa7f577..0cc9c64 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -27,7 +27,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
-import android.util.Pair;
import android.view.SurfaceControl;
import libcore.util.NativeAllocationRegistry;
@@ -73,14 +72,14 @@
*/
public static ScreenshotHardwareBuffer captureDisplay(
DisplayCaptureArgs captureArgs) {
- Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener();
- int status = captureDisplay(captureArgs, syncScreenCapture.first);
+ SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
+ int status = captureDisplay(captureArgs, syncScreenCapture);
if (status != 0) {
return null;
}
try {
- return syncScreenCapture.second.get();
+ return syncScreenCapture.getBuffer();
} catch (Exception e) {
return null;
}
@@ -133,14 +132,14 @@
* @hide
*/
public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
- Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture = createSyncCaptureListener();
- int status = captureLayers(captureArgs, syncScreenCapture.first);
+ SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
+ int status = captureLayers(captureArgs, syncScreenCapture);
if (status != 0) {
return null;
}
try {
- return syncScreenCapture.second.get();
+ return syncScreenCapture.getBuffer();
} catch (Exception e) {
return null;
}
@@ -743,14 +742,35 @@
* A helper method to handle the async screencapture callbacks synchronously. This should only
* be used if the screencapture caller doesn't care that it blocks waiting for a screenshot.
*
- * @return a Pair that holds the {@link ScreenCaptureListener} that should be used for capture
- * calls into SurfaceFlinger and a {@link ScreenshotSync} object to retrieve the results.
+ * @return a {@link SynchronousScreenCaptureListener} that should be used for capture
+ * calls into SurfaceFlinger.
*/
- public static Pair<ScreenCaptureListener, ScreenshotSync> createSyncCaptureListener() {
- final ScreenshotSync screenshotSync = new ScreenshotSync();
- final ScreenCaptureListener screenCaptureListener = new ScreenCaptureListener(
- screenshotSync::setScreenshotHardwareBuffer);
- return new Pair<>(screenCaptureListener, screenshotSync);
+ public static SynchronousScreenCaptureListener createSyncCaptureListener() {
+ ScreenshotHardwareBuffer[] bufferRef = new ScreenshotHardwareBuffer[1];
+ CountDownLatch latch = new CountDownLatch(1);
+ Consumer<ScreenshotHardwareBuffer> consumer = buffer -> {
+ bufferRef[0] = buffer;
+ latch.countDown();
+ };
+
+ return new SynchronousScreenCaptureListener(consumer) {
+ // In order to avoid requiring two GC cycles to clean up the consumer and the buffer
+ // it references, the underlying JNI listener holds a weak reference to the consumer.
+ // This property exists to ensure the consumer stays alive during the listener's
+ // lifetime.
+ private Consumer<ScreenshotHardwareBuffer> mConsumer = consumer;
+
+ @Override
+ public ScreenshotHardwareBuffer getBuffer() {
+ try {
+ latch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
+ return bufferRef[0];
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to wait for screen capture result", e);
+ return null;
+ }
+ }
+ };
}
/**
@@ -758,28 +778,15 @@
* {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} or
* {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)}
*/
- public static class ScreenshotSync {
- private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
- private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
-
- private void setScreenshotHardwareBuffer(
- ScreenshotHardwareBuffer screenshotHardwareBuffer) {
- mScreenshotHardwareBuffer = screenshotHardwareBuffer;
- mCountDownLatch.countDown();
+ public abstract static class SynchronousScreenCaptureListener extends ScreenCaptureListener {
+ SynchronousScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) {
+ super(consumer);
}
/**
* Get the {@link ScreenshotHardwareBuffer} synchronously. This can be null if the
* screenshot failed or if there was no callback in {@link #SCREENSHOT_WAIT_TIME_S} seconds.
*/
- public ScreenshotHardwareBuffer get() {
- try {
- mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
- return mScreenshotHardwareBuffer;
- } catch (Exception e) {
- Log.e(TAG, "Failed to wait for screen capture result", e);
- return null;
- }
- }
+ public abstract ScreenshotHardwareBuffer getBuffer();
}
}
diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java
index cfbeeff..7fc55a7 100644
--- a/core/java/android/window/WindowInfosListenerForTest.java
+++ b/core/java/android/window/WindowInfosListenerForTest.java
@@ -58,6 +58,11 @@
public final String name;
/**
+ * The display id the window is on.
+ */
+ public final int displayId;
+
+ /**
* The window's position and size in display space.
*/
@NonNull
@@ -73,14 +78,23 @@
*/
public final boolean isVisible;
- WindowInfo(@NonNull IBinder windowToken, @NonNull String name, @NonNull Rect bounds,
- int inputConfig) {
+ WindowInfo(@NonNull IBinder windowToken, @NonNull String name, int displayId,
+ @NonNull Rect bounds, int inputConfig) {
this.windowToken = windowToken;
this.name = name;
+ this.displayId = displayId;
this.bounds = bounds;
this.isTrustedOverlay = (inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
this.isVisible = (inputConfig & InputConfig.NOT_VISIBLE) == 0;
}
+
+ @Override
+ public String toString() {
+ return name + ", frame=" + bounds
+ + ", isVisible=" + isVisible
+ + ", isTrustedOverlay=" + isTrustedOverlay
+ + ", token=" + windowToken;
+ }
}
private static final String TAG = "WindowInfosListenerForTest";
@@ -139,8 +153,8 @@
for (var handle : windowHandles) {
var bounds = new Rect(handle.frameLeft, handle.frameTop, handle.frameRight,
handle.frameBottom);
- windowInfos.add(new WindowInfo(handle.getWindowToken(), handle.name, bounds,
- handle.inputConfig));
+ windowInfos.add(new WindowInfo(handle.getWindowToken(), handle.name, handle.displayId,
+ bounds, handle.inputConfig));
}
return windowInfos;
}
diff --git a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
index ec2d2ef..980b92c 100644
--- a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
@@ -63,7 +63,7 @@
mAlertParams.mTitle =
getString(R.string.app_streaming_blocked_title_for_permission_dialog);
mAlertParams.mMessage =
- getString(R.string.app_streaming_blocked_message, streamedDeviceName);
+ getString(R.string.app_streaming_blocked_message_for_permission_request);
} else if (TextUtils.equals(activityInfo.packageName, BLOCKED_COMPONENT_PLAYSTORE)) {
mAlertParams.mTitle =
getString(R.string.app_streaming_blocked_title_for_playstore_dialog);
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 9ffccb3..385612d 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -552,12 +552,6 @@
"task_manager_inform_job_scheduler_of_pending_app_stop";
/**
- * (boolean) Whether widget provider info would be saved to / loaded from system persistence
- * layer as opposed to individual manifests in respective apps.
- */
- public static final String PERSISTS_WIDGET_PROVIDER_INFO = "persists_widget_provider_info";
-
- /**
* (boolean) Whether to show smart chips (based on TextClassifier) in the clipboard overlay.
*/
public static final String CLIPBOARD_OVERLAY_SHOW_ACTIONS = "clipboard_overlay_show_actions";
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 4cbf475..76e0e34 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -30,7 +30,6 @@
import com.android.internal.os.BackgroundThread;
-import java.util.HashSet;
import java.util.Objects;
/**
@@ -43,8 +42,6 @@
final IntentFilter mPackageFilt;
final IntentFilter mNonDataFilt;
final IntentFilter mExternalFilt;
-
- final HashSet<String> mUpdatingPackages = new HashSet<String>();
Context mRegisteredContext;
Handler mRegisteredHandler;
@@ -139,13 +136,6 @@
mRegisteredContext = null;
}
- //not yet implemented
- boolean isPackageUpdating(String packageName) {
- synchronized (mUpdatingPackages) {
- return mUpdatingPackages.contains(packageName);
- }
- }
-
public void onBeginPackageChanges() {
}
@@ -343,7 +333,7 @@
mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
if (mChangeUserId == UserHandle.USER_NULL) {
- Slog.w("PackageMonitor", "Intent broadcast does not contain user handle: " + intent);
+ Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
return;
}
onBeginPackageChanges();
@@ -373,11 +363,6 @@
onPackageAdded(pkg, uid);
}
onPackageAppeared(pkg, mChangeType);
- if (mChangeType == PACKAGE_UPDATING) {
- synchronized (mUpdatingPackages) {
- mUpdatingPackages.remove(pkg);
- }
- }
}
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
String pkg = getPackageName(intent);
@@ -387,10 +372,6 @@
mTempArray[0] = pkg;
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
mChangeType = PACKAGE_UPDATING;
- synchronized (mUpdatingPackages) {
- //not used for now
- //mUpdatingPackages.add(pkg);
- }
onPackageUpdateStarted(pkg, uid);
} else {
mChangeType = PACKAGE_PERMANENT_CHANGE;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 66e3333..1a38049 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -20,6 +20,7 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
@@ -105,14 +106,10 @@
*
* @param vis visibility flags
* @param backDisposition disposition flags
- * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
- * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
- * @see android.inputmethodservice.InputMethodService#IME_INVISIBLE
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
*/
@AnyThread
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index fdcb87f..dde38aa 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -259,6 +259,8 @@
}
private TraceDelegate mTracer;
+ private int mTraceLastState = 0;
+ private int mTraceLastState2 = 0;
/**
* Constructor
@@ -1241,7 +1243,6 @@
*/
private void recordTraceEvents(int code, HistoryTag tag) {
if (code == HistoryItem.EVENT_NONE) return;
- if (!mTracer.tracingEnabled()) return;
final int idx = code & HistoryItem.EVENT_TYPE_MASK;
final String prefix = (code & HistoryItem.EVENT_FLAG_START) != 0 ? "+" :
@@ -1270,8 +1271,6 @@
* Writes changes to a HistoryItem state bitmap to Atrace.
*/
private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
- if (!mTracer.tracingEnabled()) return;
-
int diff = oldval ^ newval;
if (diff == 0) return;
@@ -1324,6 +1323,16 @@
}
private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
+ if (mTracer != null && mTracer.tracingEnabled()) {
+ recordTraceEvents(cur.eventCode, cur.eventTag);
+ recordTraceCounters(mTraceLastState, cur.states,
+ BatteryStats.HISTORY_STATE_DESCRIPTIONS);
+ recordTraceCounters(mTraceLastState2, cur.states2,
+ BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
+ mTraceLastState = cur.states;
+ mTraceLastState2 = cur.states2;
+ }
+
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
@@ -1345,12 +1354,6 @@
+ Integer.toHexString(lastDiffStates2));
}
- recordTraceEvents(cur.eventCode, cur.eventTag);
- recordTraceCounters(mHistoryLastWritten.states,
- cur.states, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
- recordTraceCounters(mHistoryLastWritten.states2,
- cur.states2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
-
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
&& (diffStates2 & lastDiffStates2) == 0
@@ -1542,7 +1545,7 @@
State2 change int: if C in the first token is set,
31 23 15 7 0
- █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | | █ |B|B|B|A|A|A|A█
+ █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | |N█N|B|B|B|A|A|A|A█
A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}.
B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4.
@@ -1557,6 +1560,7 @@
K: wifi was running.
L: video was playing.
M: power save mode was on.
+ N: 2 bits indicating the gps signal strength: poor, good, none.
Wakelock/wakereason struct: if D in the first token is set,
Event struct: if E in the first token is set,
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index a95ce64..7f53cb4 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -771,7 +771,7 @@
Zygote.applyInvokeWithSystemProperty(parsedArgs);
if (Zygote.nativeSupportsMemoryTagging()) {
- String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
+ String mode = SystemProperties.get("persist.arm64.memtag.system_server", "");
if (mode.isEmpty()) {
/* The system server has ASYNC MTE by default, in order to allow
* system services to specify their own MTE level later, as you
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 15f70f3..af1fdd7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1111,8 +1111,13 @@
: controller.getSystemBarsAppearance();
if (insets != null) {
- final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
- getResources().getConfiguration().windowConfiguration.getWindowingMode());
+ mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
+
+ final boolean clearsCompatInsets =
+ clearsCompatInsets(attrs.type, attrs.flags,
+ getResources().getConfiguration().windowConfiguration
+ .getWindowingMode())
+ && !mLastShouldAlwaysConsumeSystemBars;
final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars());
final Insets systemInsets = clearsCompatInsets
@@ -1143,7 +1148,6 @@
disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
mLastHasLeftStableInset = hasLeftStableInset;
- mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
mLastSuppressScrimTypes = insets.getSuppressScrimTypes();
}
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 4f827cd..8b9a991 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -16,6 +16,7 @@
package com.android.internal.statusbar;
+import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,7 +32,9 @@
public final int mDisabledFlags1; // switch[0]
public final int mAppearance; // switch[1]
public final AppearanceRegion[] mAppearanceRegions; // switch[2]
+ @InputMethodService.ImeWindowVisibility
public final int mImeWindowVis; // switch[3]
+ @InputMethodService.BackDispositionMode
public final int mImeBackDisposition; // switch[4]
public final boolean mShowImeSwitcher; // switch[5]
public final int mDisabledFlags2; // switch[6]
@@ -44,10 +47,12 @@
public final LetterboxDetails[] mLetterboxDetails;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
- int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
- int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
- boolean navbarColorManagedByIme, int behavior, int requestedVisibleTypes,
- String packageName, int transientBarTypes, LetterboxDetails[] letterboxDetails) {
+ int appearance, AppearanceRegion[] appearanceRegions,
+ @InputMethodService.ImeWindowVisibility int imeWindowVis,
+ @InputMethodService.BackDispositionMode int imeBackDisposition, boolean showImeSwitcher,
+ int disabledFlags2, IBinder imeToken, boolean navbarColorManagedByIme, int behavior,
+ int requestedVisibleTypes, String packageName, int transientBarTypes,
+ LetterboxDetails[] letterboxDetails) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 8a02dd6..dadeb2b 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -60,9 +60,7 @@
@UnsupportedAppUsage(maxTargetSdk = 28)
void notifyCallForwardingChanged(boolean cfi);
void notifyCallForwardingChangedForSubscriber(in int subId, boolean cfi);
- @UnsupportedAppUsage(maxTargetSdk = 28)
- void notifyDataActivity(int state);
- void notifyDataActivityForSubscriber(in int subId, int state);
+ void notifyDataActivityForSubscriber(int phoneId, int subId, int state);
void notifyDataConnectionForSubscriber(
int phoneId, int subId, in PreciseDataConnectionState preciseState);
// Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 7e827a8..729c1c4 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -59,6 +59,10 @@
static const int BUSY_TIMEOUT_MS = 2500;
static struct {
+ jmethodID onAuthorize;
+} gAuthorizer;
+
+static struct {
jmethodID apply;
} gUnaryOperator;
@@ -70,11 +74,14 @@
// Open flags.
// Must be kept in sync with the constants defined in SQLiteDatabase.java.
enum {
- OPEN_READWRITE = 0x00000000,
- OPEN_READONLY = 0x00000001,
- OPEN_READ_MASK = 0x00000001,
- NO_LOCALIZED_COLLATORS = 0x00000010,
- CREATE_IF_NECESSARY = 0x10000000,
+ OPEN_READWRITE = 0x00000000,
+ OPEN_READONLY = 0x00000001,
+ OPEN_READ_MASK = 0x00000001,
+ NO_LOCALIZED_COLLATORS = 0x00000010,
+ ENABLE_TRACE = 0x00000100,
+ ENABLE_PROFILE = 0x00000200,
+ ENABLE_AUTHORIZER = 0x00000400,
+ CREATE_IF_NECESSARY = 0x10000000,
};
sqlite3* const db;
@@ -83,9 +90,15 @@
const String8 label;
volatile bool canceled;
+ volatile jobject authorizer;
- SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
- db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
+ SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label)
+ : db(db),
+ openFlags(openFlags),
+ path(path),
+ label(label),
+ canceled(false),
+ authorizer(NULL) {}
};
// Called each time a statement begins execution, when tracing is enabled.
@@ -108,10 +121,34 @@
return connection->canceled;
}
+static int sqliteAuthorizerCallback(void* data, int action, const char* arg3, const char* arg4,
+ const char* arg5, const char* arg6) {
+ SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
+ if (connection->authorizer) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ ScopedLocalRef<jobject> authorizerObj(env, env->NewLocalRef(connection->authorizer));
+ ScopedLocalRef<jstring> arg3String(env, env->NewStringUTF(arg3));
+ ScopedLocalRef<jstring> arg4String(env, env->NewStringUTF(arg4));
+ ScopedLocalRef<jstring> arg5String(env, env->NewStringUTF(arg5));
+ ScopedLocalRef<jstring> arg6String(env, env->NewStringUTF(arg6));
+ int res = env->CallIntMethod(authorizerObj.get(), gAuthorizer.onAuthorize, action,
+ arg3String.get(), arg4String.get(), arg5String.get(),
+ arg6String.get());
+ if (env->ExceptionCheck()) {
+ ALOGE("Exception thrown by authorizer");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return SQLITE_DENY;
+ } else {
+ return res;
+ }
+ } else {
+ return SQLITE_OK;
+ }
+}
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
- jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
- jint lookasideCnt) {
+ jstring labelStr, jint lookasideSz, jint lookasideCnt) {
int sqliteFlags;
if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
@@ -172,13 +209,16 @@
// Create wrapper object.
SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);
- // Enable tracing and profiling if requested.
- if (enableTrace) {
+ // Enable optional features if requested.
+ if (openFlags & SQLiteConnection::ENABLE_TRACE) {
sqlite3_trace(db, &sqliteTraceCallback, connection);
}
- if (enableProfile) {
+ if (openFlags & SQLiteConnection::ENABLE_PROFILE) {
sqlite3_profile(db, &sqliteProfileCallback, connection);
}
+ if (openFlags & SQLiteConnection::ENABLE_AUTHORIZER) {
+ sqlite3_set_authorizer(db, &sqliteAuthorizerCallback, connection);
+ }
ALOGV("Opened connection %p with label '%s'", db, label.string());
return reinterpret_cast<jlong>(connection);
@@ -188,6 +228,11 @@
SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
if (connection) {
+ if (connection->authorizer) {
+ env->DeleteGlobalRef(connection->authorizer);
+ connection->authorizer = NULL;
+ }
+
ALOGV("Closing connection %p", connection->db);
int err = sqlite3_close(connection->db);
if (err != SQLITE_OK) {
@@ -201,6 +246,20 @@
}
}
+static void nativeSetAuthorizer(JNIEnv* env, jclass clazz, jlong connectionPtr,
+ jobject authorizerObj) {
+ SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+
+ if (connection->authorizer) {
+ env->DeleteGlobalRef(connection->authorizer);
+ connection->authorizer = NULL;
+ }
+ if (authorizerObj) {
+ jobject authorizerObjGlobal = env->NewGlobalRef(authorizerObj);
+ connection->authorizer = authorizerObjGlobal;
+ }
+}
+
static void sqliteCustomScalarFunctionCallback(sqlite3_context *context,
int argc, sqlite3_value **argv) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -885,69 +944,53 @@
return sqlite3_last_insert_rowid(connection->db);
}
-static const JNINativeMethod sMethods[] =
-{
- /* name, signature, funcPtr */
- { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
- (void*)nativeOpen },
- { "nativeClose", "(J)V",
- (void*)nativeClose },
- { "nativeRegisterCustomScalarFunction", "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
- (void*)nativeRegisterCustomScalarFunction },
- { "nativeRegisterCustomAggregateFunction", "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
- (void*)nativeRegisterCustomAggregateFunction },
- { "nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
- (void*)nativeRegisterLocalizedCollators },
- { "nativePrepareStatement", "(JLjava/lang/String;)J",
- (void*)nativePrepareStatement },
- { "nativeFinalizeStatement", "(JJ)V",
- (void*)nativeFinalizeStatement },
- { "nativeGetParameterCount", "(JJ)I",
- (void*)nativeGetParameterCount },
- { "nativeIsReadOnly", "(JJ)Z",
- (void*)nativeIsReadOnly },
- { "nativeGetColumnCount", "(JJ)I",
- (void*)nativeGetColumnCount },
- { "nativeGetColumnName", "(JJI)Ljava/lang/String;",
- (void*)nativeGetColumnName },
- { "nativeBindNull", "(JJI)V",
- (void*)nativeBindNull },
- { "nativeBindLong", "(JJIJ)V",
- (void*)nativeBindLong },
- { "nativeBindDouble", "(JJID)V",
- (void*)nativeBindDouble },
- { "nativeBindString", "(JJILjava/lang/String;)V",
- (void*)nativeBindString },
- { "nativeBindBlob", "(JJI[B)V",
- (void*)nativeBindBlob },
- { "nativeResetStatementAndClearBindings", "(JJ)V",
- (void*)nativeResetStatementAndClearBindings },
- { "nativeExecute", "(JJZ)V",
- (void*)nativeExecute },
- { "nativeExecuteForLong", "(JJ)J",
- (void*)nativeExecuteForLong },
- { "nativeExecuteForString", "(JJ)Ljava/lang/String;",
- (void*)nativeExecuteForString },
- { "nativeExecuteForBlobFileDescriptor", "(JJ)I",
- (void*)nativeExecuteForBlobFileDescriptor },
- { "nativeExecuteForChangedRowCount", "(JJ)I",
- (void*)nativeExecuteForChangedRowCount },
- { "nativeExecuteForLastInsertedRowId", "(JJ)J",
- (void*)nativeExecuteForLastInsertedRowId },
- { "nativeExecuteForCursorWindow", "(JJJIIZ)J",
- (void*)nativeExecuteForCursorWindow },
- { "nativeGetDbLookaside", "(J)I",
- (void*)nativeGetDbLookaside },
- { "nativeCancel", "(J)V",
- (void*)nativeCancel },
- { "nativeResetCancel", "(JZ)V",
- (void*)nativeResetCancel },
+static const JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeOpen", "(Ljava/lang/String;ILjava/lang/String;II)J", (void*)nativeOpen},
+ {"nativeClose", "(J)V", (void*)nativeClose},
+ {"nativeSetAuthorizer", "(JLandroid/database/sqlite/SQLiteAuthorizer;)V",
+ (void*)nativeSetAuthorizer},
+ {"nativeRegisterCustomScalarFunction",
+ "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
+ (void*)nativeRegisterCustomScalarFunction},
+ {"nativeRegisterCustomAggregateFunction",
+ "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
+ (void*)nativeRegisterCustomAggregateFunction},
+ {"nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
+ (void*)nativeRegisterLocalizedCollators},
+ {"nativePrepareStatement", "(JLjava/lang/String;)J", (void*)nativePrepareStatement},
+ {"nativeFinalizeStatement", "(JJ)V", (void*)nativeFinalizeStatement},
+ {"nativeGetParameterCount", "(JJ)I", (void*)nativeGetParameterCount},
+ {"nativeIsReadOnly", "(JJ)Z", (void*)nativeIsReadOnly},
+ {"nativeGetColumnCount", "(JJ)I", (void*)nativeGetColumnCount},
+ {"nativeGetColumnName", "(JJI)Ljava/lang/String;", (void*)nativeGetColumnName},
+ {"nativeBindNull", "(JJI)V", (void*)nativeBindNull},
+ {"nativeBindLong", "(JJIJ)V", (void*)nativeBindLong},
+ {"nativeBindDouble", "(JJID)V", (void*)nativeBindDouble},
+ {"nativeBindString", "(JJILjava/lang/String;)V", (void*)nativeBindString},
+ {"nativeBindBlob", "(JJI[B)V", (void*)nativeBindBlob},
+ {"nativeResetStatementAndClearBindings", "(JJ)V",
+ (void*)nativeResetStatementAndClearBindings},
+ {"nativeExecute", "(JJZ)V", (void*)nativeExecute},
+ {"nativeExecuteForLong", "(JJ)J", (void*)nativeExecuteForLong},
+ {"nativeExecuteForString", "(JJ)Ljava/lang/String;", (void*)nativeExecuteForString},
+ {"nativeExecuteForBlobFileDescriptor", "(JJ)I", (void*)nativeExecuteForBlobFileDescriptor},
+ {"nativeExecuteForChangedRowCount", "(JJ)I", (void*)nativeExecuteForChangedRowCount},
+ {"nativeExecuteForLastInsertedRowId", "(JJ)J", (void*)nativeExecuteForLastInsertedRowId},
+ {"nativeExecuteForCursorWindow", "(JJJIIZ)J", (void*)nativeExecuteForCursorWindow},
+ {"nativeGetDbLookaside", "(J)I", (void*)nativeGetDbLookaside},
+ {"nativeCancel", "(J)V", (void*)nativeCancel},
+ {"nativeResetCancel", "(JZ)V", (void*)nativeResetCancel},
- { "nativeLastInsertRowId", "(J)I", (void*) nativeLastInsertRowId }
-};
+ {"nativeLastInsertRowId", "(J)I", (void*)nativeLastInsertRowId}};
int register_android_database_SQLiteConnection(JNIEnv *env)
{
+ jclass authorizerClazz = FindClassOrDie(env, "android/database/sqlite/SQLiteAuthorizer");
+ gAuthorizer.onAuthorize = GetMethodIDOrDie(env, authorizerClazz, "onAuthorize",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/"
+ "String;Ljava/lang/String;)I");
+
jclass unaryClazz = FindClassOrDie(env, "java/util/function/UnaryOperator");
gUnaryOperator.apply = GetMethodIDOrDie(env, unaryClazz,
"apply", "(Ljava/lang/Object;)Ljava/lang/Object;");
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 416d991..eb5f297 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -163,10 +163,9 @@
mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
- mInfo.ownerPid = env->GetIntField(obj,
- gInputWindowHandleClassInfo.ownerPid);
- mInfo.ownerUid = env->GetIntField(obj,
- gInputWindowHandleClassInfo.ownerUid);
+ mInfo.ownerPid = gui::Pid{env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid)};
+ mInfo.ownerUid = gui::Uid{
+ static_cast<uid_t>(env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid))};
mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
mInfo.displayId = env->GetIntField(obj,
gInputWindowHandleClassInfo.displayId);
@@ -308,8 +307,10 @@
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
static_cast<int32_t>(windowInfo.touchOcclusionMode));
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid, windowInfo.ownerUid);
+ env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid,
+ windowInfo.ownerPid.val());
+ env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid,
+ windowInfo.ownerUid.val());
ScopedLocalRef<jstring> packageName(env, env->NewStringUTF(windowInfo.packageName.data()));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
packageName.get());
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 01dbceb..d94b982 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -49,10 +49,10 @@
appPackageNameChars.c_str(), vulkanVersion);
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring packageName,
jstring devOptIn, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
- ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars packageNameChars(env, packageName);
ScopedUtfChars devOptInChars(env, devOptIn);
std::vector<std::string> features;
@@ -73,15 +73,10 @@
}
}
- android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
+ android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), packageNameChars.c_str(),
devOptInChars.c_str(), features);
}
-bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
- ScopedUtfChars appNameChars(env, appName);
- return android::GraphicsEnv::getInstance().shouldUseAngle(appNameChars.c_str());
-}
-
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader(
env, classLoader);
@@ -126,8 +121,6 @@
{"setAngleInfo",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
- {"getShouldUseAngle", "(Ljava/lang/String;)Z",
- reinterpret_cast<void*>(shouldUseAngle_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
reinterpret_cast<void*>(setLayerPaths_native)},
{"setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native)},
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 986dbe9..e729750 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -81,22 +81,28 @@
public:
explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
env->GetJavaVM(&mVm);
- mConsumerObject = env->NewGlobalRef(jobject);
- LOG_ALWAYS_FATAL_IF(!mConsumerObject, "Failed to make global ref");
+ mConsumerWeak = env->NewWeakGlobalRef(jobject);
}
~ScreenCaptureListenerWrapper() {
- if (mConsumerObject) {
- getenv()->DeleteGlobalRef(mConsumerObject);
- mConsumerObject = nullptr;
+ if (mConsumerWeak) {
+ getenv()->DeleteWeakGlobalRef(mConsumerWeak);
+ mConsumerWeak = nullptr;
}
}
binder::Status onScreenCaptureCompleted(
const gui::ScreenCaptureResults& captureResults) override {
JNIEnv* env = getenv();
+
+ ScopedLocalRef<jobject> consumer{env, env->NewLocalRef(mConsumerWeak)};
+ if (consumer == nullptr) {
+ ALOGE("ScreenCaptureListenerWrapper consumer not alive.");
+ return binder::Status::ok();
+ }
+
if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
- env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, nullptr);
+ env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, nullptr);
checkAndClearException(env, "accept");
return binder::Status::ok();
}
@@ -111,7 +117,7 @@
captureResults.capturedSecureLayers,
captureResults.capturedHdrLayers);
checkAndClearException(env, "builder");
- env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, screenshotHardwareBuffer);
+ env->CallVoidMethod(consumer.get(), gConsumerClassInfo.accept, screenshotHardwareBuffer);
checkAndClearException(env, "accept");
env->DeleteLocalRef(jhardwareBuffer);
env->DeleteLocalRef(screenshotHardwareBuffer);
@@ -119,7 +125,7 @@
}
private:
- jobject mConsumerObject;
+ jweak mConsumerWeak;
JavaVM* mVm;
JNIEnv* getenv() {
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index a95b6e3..76f5c10 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -127,16 +127,17 @@
}
}
-static void throwReadRE(JNIEnv *env, binder_status_t status) {
+static void throwReadException(JNIEnv *env, binder_status_t status) {
ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
- jniThrowRuntimeException(env, "Could not read LongArrayMultiStateCounter from Parcel");
+ jniThrowException(env, "android.os.BadParcelableException",
+ "Could not read LongArrayMultiStateCounter from Parcel");
}
#define THROW_AND_RETURN_ON_READ_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
- throwReadRE(env, status); \
+ throwReadException(env, status); \
return 0L; \
} \
}
@@ -147,6 +148,11 @@
int32_t stateCount;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
+ if (stateCount < 0 || stateCount > 0xEFFF) {
+ throwReadException(env, STATUS_INVALID_OPERATION);
+ return 0L;
+ }
+
int32_t arrayLength;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength));
diff --git a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
index 1712b3a8..ddf7a67 100644
--- a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
@@ -131,16 +131,17 @@
}
}
-static void throwReadRE(JNIEnv *env, binder_status_t status) {
+static void throwReadException(JNIEnv *env, binder_status_t status) {
ALOGE("Could not read LongMultiStateCounter from Parcel, status = %d", status);
- jniThrowRuntimeException(env, "Could not read LongMultiStateCounter from Parcel");
+ jniThrowException(env, "android.os.BadParcelableException",
+ "Could not read LongMultiStateCounter from Parcel");
}
#define THROW_AND_RETURN_ON_READ_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
- throwReadRE(env, status); \
+ throwReadException(env, status); \
return 0L; \
} \
}
@@ -151,6 +152,11 @@
int32_t stateCount;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
+ if (stateCount < 0 || stateCount > 0xEFFF) {
+ throwReadException(env, STATUS_INVALID_OPERATION);
+ return 0L;
+ }
+
auto counter = std::make_unique<battery::LongMultiStateCounter>(stateCount, 0);
for (battery::state_t state = 0; state < stateCount; state++) {
diff --git a/core/proto/android/companion/telecom.proto b/core/proto/android/companion/telecom.proto
index 7fe24670..73dd8dd 100644
--- a/core/proto/android/companion/telecom.proto
+++ b/core/proto/android/companion/telecom.proto
@@ -88,6 +88,8 @@
string name = 1;
// Unique identifier for this facilitator, such as a package name.
string identifier = 2;
+ // Extended identifier for this facilitator.
+ string extended_identifier = 3;
}
enum Control {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 698e572..0c8707d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6102,7 +6102,7 @@
<!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register
for callbacks when apps reach a certain usage time limit, etc. -->
<permission android:name="android.permission.OBSERVE_APP_USAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|role" />
<!-- @hide @TestApi @SystemApi Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
@@ -6732,7 +6732,7 @@
it will be ignored.
@hide -->
<permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|role" />
<!-- @SystemApi Allows entering or exiting car mode using a specified priority.
This permission is required to use UiModeManager while specifying a priority for the calling
diff --git a/core/res/OWNERS b/core/res/OWNERS
index bce500c..b46902e 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -33,6 +33,9 @@
# Multiuser
per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
+# Battery Saver
+per-file res/values/config_battery_saver.xml = file:/services/core/java/com/android/server/power/batterysaver/OWNERS
+
# Car
per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
diff --git a/core/res/res/anim-watch/rounded_window_enter.xml b/core/res/res/anim-watch/rounded_window_enter.xml
new file mode 100644
index 0000000..b9ec8d6
--- /dev/null
+++ b/core/res/res/anim-watch/rounded_window_enter.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="normal" android:hasRoundedCorners="true" android:shareInterpolator="false"
+ android:detachWallpaper="true">
+ <scale android:fromXScale="0.75" android:toXScale="1.0"
+ android:fromYScale="0.75" android:toYScale="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@interpolator/rounded_window_interpolator"
+ android:duration="250"/>
+ <alpha android:fromAlpha="0.25" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:duration="150"
+ android:interpolator="@android:interpolator/rounded_window_interpolator"/>
+</set>
diff --git a/core/res/res/anim-watch/rounded_window_exit.xml b/core/res/res/anim-watch/rounded_window_exit.xml
new file mode 100644
index 0000000..757b851
--- /dev/null
+++ b/core/res/res/anim-watch/rounded_window_exit.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:zAdjustment="normal" android:hasRoundedCorners="true" android:shareInterpolator="false"
+ android:detachWallpaper="true">
+ <scale android:fromXScale="1.0" android:toXScale="0.75"
+ android:fromYScale="1.0" android:toYScale="0.75"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@interpolator/rounded_window_interpolator"
+ android:duration="250"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:duration="250"
+ android:interpolator="@android:interpolator/rounded_window_interpolator"/>
+</set>
diff --git a/core/res/res/drawable/ic_bluetooth_share_icon.xml b/core/res/res/drawable/ic_bluetooth_share_icon.xml
deleted file mode 100644
index 6acfd57..0000000
--- a/core/res/res/drawable/ic_bluetooth_share_icon.xml
+++ /dev/null
@@ -1,27 +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.
--->
-<!-- This drawable should only be used by the Bluetooth application for its share target icon. -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="@*android:color/accent_device_default_light">
-
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-</vector>
diff --git a/core/res/res/interpolator-watch/rounded_window_interpolator.xml b/core/res/res/interpolator-watch/rounded_window_interpolator.xml
new file mode 100644
index 0000000..c322169
--- /dev/null
+++ b/core/res/res/interpolator-watch/rounded_window_interpolator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="0"
+ android:controlX2="0.2"
+ android:controlY2="1" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 856732c..7319425 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometriese hardeware is nie beskikbaar nie"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Stawing is gekanselleer"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nie herken nie"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Gesig word nie herken nie"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Stawing is gekanselleer"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen PIN, patroon of wagwoord is gestel nie"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Kon nie staaf nie"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Swiep van bo na onder as jy wil uitgaan."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Het dit"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Draai vir ’n beter aansig"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Verlaat gedeelde skerm vir ’n beter aansig"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Maak <xliff:g id="NAME">%s</xliff:g> in volskerm oop vir ’n beter aansig"</string>
<string name="done_label" msgid="7283767013231718521">"Klaar"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ure se sirkelglyer"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minute se sirkelglyer"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 5c222cd..6643a07 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ማረጋገጥ ተሰርዟል"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"አልታወቀም"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"መልክ አልታወቀም"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ማረጋገጥ ተሰርዟል"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ምንም ፒን፣ ሥርዓተ ጥለት ወይም የይለፍ ቃል አልተቀናበረም"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ማረጋገጥ ላይ ስህተት"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ገባኝ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ለተሻለ ዕይታ ያሽከርክሩ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ለተሻለ ዕይታ የተከፈለ ማያ ገጽን ትተው ይውጡ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ለተሻለ ዕይታ <xliff:g id="NAME">%s</xliff:g>ን በሙሉ ገጽ ዕይታ ይክፈቱ"</string>
<string name="done_label" msgid="7283767013231718521">"ተከናውኗል"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"የሰዓታት ክብ ተንሸራታች"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"የደቂቃዎች ክብ ተንሸራታች"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 245902a..33209eb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -626,6 +626,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"معدّات المقاييس الحيوية غير متاحة."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تم إلغاء المصادقة."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"لم يتم التعرف عليها."</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"لم يتم التعرّف على الوجه."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"تم إلغاء المصادقة."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"لم يتم ضبط رقم تعريف شخصي أو نقش أو كلمة مرور."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خطأ في المصادقة"</string>
@@ -1856,7 +1857,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"حسنًا"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"يمكنك تدوير الجهاز لرؤية شاشة معاينة الكاميرا بشكل أوضح."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"يمكنك الخروج من وضع \"تقسيم الشاشة\" لرؤية شاشة معاينة الكاميرا بشكل أوضح."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"عليك فتح \"<xliff:g id="NAME">%s</xliff:g>\" في وضع ملء الشاشة لرؤية شاشة معاينة الكاميرا بشكل أوضح."</string>
<string name="done_label" msgid="7283767013231718521">"تم"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"شريط التمرير الدائري للساعات"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"شريط التمرير الدائري للدقائق"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a8c8566..838586f 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"চিনাক্ত কৰিব পৰা নাই"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"মুখাৱয়ব চিনি পোৱা নাই"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"কোনো পিন, আৰ্হি বা পাছৱৰ্ড ছেট কৰা নাই"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"আসোঁৱাহৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰি থকা হৈছে"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"বাহিৰ হ\'বলৈ ওপৰৰপৰা তললৈ ছোৱাইপ কৰক।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"বুজি পালোঁ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ভালকৈ চাবলৈ ঘূৰাওক"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ভালকৈ চাবলৈ বিভাজিত স্ক্ৰীনৰ পৰা বাহিৰ হওক"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ভালকৈ চাবলৈ <xliff:g id="NAME">%s</xliff:g> পূৰ্ণ স্ক্ৰীনত খোলক"</string>
<string name="done_label" msgid="7283767013231718521">"সম্পন্ন কৰা হ’ল"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ঘড়ীৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"মিনিটৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index d9cce7b..bf0b3b4 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik proqram əlçatan deyil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Doğrulama ləğv edildi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmır"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Üz tanınmadı"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Doğrulama ləğv edildi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, nümunə və ya parol ayarlanmayıb"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Doğrulama zamanı xəta baş verdi"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Çıxmaq üçün yuxarıdan aşağı sürüşdürün."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Anladım"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Daha yaxşı görünüş üçün fırladın"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Daha yaxşı görünüş üçün bölünmüş ekrandan çıxın"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Yaxşı görmək üçün <xliff:g id="NAME">%s</xliff:g> tətbiqini tam ekranda açın"</string>
<string name="done_label" msgid="7283767013231718521">"Hazırdır"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Dairəvi saat slayderi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Dairəvi dəqiqə slayderi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0f2a5ea..1d96814e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -623,16 +623,17 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Potvrda identiteta je otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Lice nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Potvrda identiteta je otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Niste podesili ni PIN, ni šablon, ni lozinku"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri potvrdi identiteta"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristite zaključavanje ekrana"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Upotrebite zaključavanje ekrana da biste nastavili"</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Jako pritisnite senzor"</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Čvrsto pritisnite senzor"</string>
<string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Prepoznavanje otiska prsta nije uspelo. Probajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Obrišite senzor za otisak prsta i probajte ponovo"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Obrišite senzor i probajte ponovo"</string>
- <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Jako pritisnite senzor"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probajte sa drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Previše je svetlo"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Da biste izašli, prevucite nadole odozgo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Važi"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotirajte radi boljeg prikaza"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Izađite iz podeljenog ekrana radi boljeg prikaza"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otvorite aplikaciju <xliff:g id="NAME">%s</xliff:g> preko celog ekrana da biste bolje videli"</string>
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač za sate"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač za minute"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3b7eae5..a0ba0a9 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -624,16 +624,17 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біяметрычнае абсталяванне недаступнае"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аўтэнтыфікацыя скасавана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не распазнана"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Твар не распазнаны"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аўтэнтыфікацыя скасавана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не заданы PIN-код, узор разблакіроўкі або пароль"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Памылка аўтэнтыфікацыі"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ужываць блакіроўку экрана"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Каб працягнуць, скарыстайце свой сродак блакіроўкі экрана"</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Моцна націсніце на сканер"</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Шчыльна прыкладзіце палец да сканера"</string>
<string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не ўдалося распазнаць адбітак пальца. Паўтарыце спробу."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Ачысціце сканер адбіткаў пальцаў і паўтарыце спробу"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Ачысціце сканер і паўтарыце спробу"</string>
- <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Моцна націсніце на сканер"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Шчыльна прыкладзіце палец да сканера"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Палец рухаўся занадта павольна. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Паспрабуйце іншы адбітак пальца"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Занадта светла"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Для выхаду правядзіце зверху ўніз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Зразумела"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Павярнуць для лепшага прагляду"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Выйсці з рэжыму падзеленага экрана для лепшага прагляду"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Для больш зручнага прагляду адкрыйце праграму \"<xliff:g id="NAME">%s</xliff:g>\", выкарыстоўваючы поўнаэкранны рэжым"</string>
<string name="done_label" msgid="7283767013231718521">"Гатова"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кругавы паўзунок гадзін"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кругавы паўзунок хвілін"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a0790eb..6f7ed4a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометричният хардуер не е налице"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Удостоверяването бе анулирано"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не е разпознато"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Лицето не е разпознато"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Удостоверяването бе анулирано"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Няма зададен ПИН код, фигура или парола"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при удостоверяването"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"За изход плъзнете пръст надолу от горната част."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Разбрах"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Завъртете за по-добър изглед"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Излезте от разделения екран за по-добър изглед"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Отворете <xliff:g id="NAME">%s</xliff:g> на цял екран за по-добър изглед"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кръгов плъзгач за часовете"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кръгов плъзгач за минутите"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index d3dbe6a..7c3b25aa 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"যাচাইকরণ বাতিল হয়েছে"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"স্বীকৃত নয়"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ফেস চেনা যায়নি"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"যাচাইকরণ বাতিল হয়েছে"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"পিন, প্যাটার্ন অথবা পাসওয়ার্ড সেট করা নেই"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"যাচাইকরণে সমস্যা হয়েছে"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"প্রস্থান করতে উপর থেকে নিচের দিকে সোয়াইপ করুন"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"বুঝেছি"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"আরও ভাল ক্যামেরা ভিউ পাওয়ার জন্য ঘোরান"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"আরও ভাল ক্যামেরা ভিউ পাওয়ার জন্য স্প্লিট স্ক্রিন থেকে বেরিয়ে আসুন"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"আরও ভাল ভিউয়ের জন্য ফুল স্ক্রিনে <xliff:g id="NAME">%s</xliff:g> খুলুন"</string>
<string name="done_label" msgid="7283767013231718521">"সম্পন্ন হয়েছে"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"বৃত্তাকার ঘণ্টা নির্বাচকের স্লাইডার"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e917d6b..de566ab 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -623,13 +623,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija je otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Lice nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija je otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nije postavljen PIN, uzorak niti lozinka"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri autentifikaciji"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristi zaključavanje ekrana"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Unesite zaključavanje ekrana da nastavite"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Čvrsto pritisnite senzor"</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Nije moguće prepoznati otisak prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Otisak prsta nije prepoznat. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite senzor za otisak prsta i pokušajte ponovo"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite senzor i pokušajte ponovo"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Da izađete, prevucite odozgo nadolje."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Razumijem"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotirajte za bolji prikaz"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Izađite iz podijeljenog ekrana za bolji prikaz"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otvorite aplikaciju <xliff:g id="NAME">%s</xliff:g> preko cijelog ekrana radi boljeg pregleda"</string>
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač za odabir sata"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač za minute"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5d8c861..2902d53 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No s\'ha reconegut"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"No s\'ha reconegut la cara"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha definit cap PIN, patró o contrasenya"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error en l\'autenticació"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Per sortir, llisca cap avall des de la part superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entesos"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Gira per a una millor visualització"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Surt de la pantalla dividida per a una millor visualització"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Obre <xliff:g id="NAME">%s</xliff:g> en pantalla completa per a una millor visualització"</string>
<string name="done_label" msgid="7283767013231718521">"Fet"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control circular de les hores"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control circular dels minuts"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 87a8100..718bc05 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardware není k dispozici"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ověření bylo zrušeno"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznáno"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Obličej nebyl rozpoznán"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ověření bylo zrušeno"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Není nastaven žádný PIN, gesto ani heslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Při ověřování došlo k chybě"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Režim ukončíte přejetím prstem shora dolů."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Rozumím"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Otočte obrazovku, abyste lépe viděli"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Ukončete režim rozdělené obrazovky, abyste lépe viděli"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otevřete aplikaci <xliff:g id="NAME">%s</xliff:g> na celou obrazovku, aby byla lépe vidět"</string>
<string name="done_label" msgid="7283767013231718521">"Hotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kruhový posuvník hodin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kruhový posuvník minut"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 629db59..e605287 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk hardware er ikke tilgængelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Godkendelsen blev annulleret"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke genkendt"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ansigt blev ikke genkendt"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Godkendelsen blev annulleret"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Der er ikke angivet pinkode, mønster eller adgangskode"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Der opstod fejl i forbindelse med godkendelse"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Stryg ned fra toppen for at afslutte."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK, det er forstået"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Roter, og få en bedre visning"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Afslut opdelt skærm, og få en bedre visning"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Åbn <xliff:g id="NAME">%s</xliff:g> i fuld skærm for at få en bedre visning"</string>
<string name="done_label" msgid="7283767013231718521">"Udfør"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Cirkulær timevælger"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Cirkulær minutvælger"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a1d2739..7ae7ff9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische Hardware nicht verfügbar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentifizierung abgebrochen"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nicht erkannt"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Gesicht nicht erkannt"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentifizierung abgebrochen"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Keine PIN, kein Muster und kein Passwort festgelegt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Fehler bei der Authentifizierung"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Zum Beenden von oben nach unten wischen"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ok"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Drehen, um die Ansicht zu verbessern"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Splitscreen-Modus beenden, um die Ansicht zu verbessern"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Du kannst <xliff:g id="NAME">%s</xliff:g> im Vollbildmodus öffnen, um die Ansicht zu verbessern"</string>
<string name="done_label" msgid="7283767013231718521">"Fertig"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kreisförmiger Schieberegler für Stunden"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kreisförmiger Schieberegler für Minuten"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1ddfc95..0eb6aa6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -622,13 +622,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Δεν αναγνωρίστηκε"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Το πρόσωπο δεν αναγνωρίστηκε"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Δεν έχει οριστεί PIN, μοτίβο ή κωδικός πρόσβασης"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Σφάλμα κατά τον έλεγχο ταυτότητας"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Χρήση κλειδώματος οθόνης"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Χρησιμοποιήστε το κλείδωμα οθόνης για να συνεχίσετε"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Πιέστε σταθερά τον αισθητήρα"</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Δεν είναι δυνατή η αναγνώριση του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"To δακτ. αποτύπωμα δεν αναγνωρίστηκε. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Καθαρίστε τον αισθητήρα δακτυλικών αποτυπωμάτων και δοκιμάστε ξανά"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Καθαρίστε τον αισθητήρα και δοκιμάστε ξανά"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Πιέστε σταθερά τον αισθητήρα"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Το κατάλαβα"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Περιστρέψτε την οθόνη για καλύτερη προβολή"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Εξέλθετε από τον διαχωρισμό οθόνης για καλύτερη προβολή"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Ανοίξτε την εφαρμογή <xliff:g id="NAME">%s</xliff:g> σε πλήρη οθόνη για καλύτερη προβολή"</string>
<string name="done_label" msgid="7283767013231718521">"Τέλος"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Κυκλικό ρυθμιστικό ωρών"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Κυκλικό ρυθμιστικό λεπτών"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index b9e033c..cdb20d0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Face not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Exit split screen for a better view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 872a41b..b0648e9 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication canceled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognized"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Face not recognized"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication canceled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern, or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error authenticating"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Exit split screen for a better view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 849ef80..d5374e1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Face not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Exit split screen for a better view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cccda58f..e0fdced 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Face not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Exit split screen for a better view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 250a3a1..d25fb70 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication canceled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognized"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Face not recognized"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication canceled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern, or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error authenticating"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotate for a better view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Exit split screen for a better view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> in full screen for a better view"</string>
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bf34761..1da5d04 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"No hay hardware biométrico disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Se canceló la autenticación"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoció"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"No se reconoció el rostro"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Se canceló la autenticación"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se estableció ningún PIN, patrón ni contraseña"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error de autenticación"</string>
@@ -1259,7 +1260,7 @@
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando aplicaciones"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Finalizando el inicio"</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Presionaste el botón de encendido. Por lo general, esta acción apaga la pantalla.\n\nPresiona suavemente mientras configuras tu huella dactilar."</string>
- <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Para finalizar, apaga la pantalla"</string>
+ <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Para salir, apaga la pantalla"</string>
<string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Apagar"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"¿Verificar huella dactilar?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Presionaste el botón de encendido. Por lo general, esta acción apaga la pantalla.\n\nPresiona suavemente para verificar tu huella dactilar."</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Gira la pantalla para obtener una mejor vista"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Sal de la pantalla dividida para obtener una mejor vista"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abre <xliff:g id="NAME">%s</xliff:g> en pantalla completa para una mejor visualización"</string>
<string name="done_label" msgid="7283767013231718521">"Listo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control deslizante circular de horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control deslizante circular de minutos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0073d2d..dc56969 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticación cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoce"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Cara no reconocida"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticación cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se ha definido el PIN, el patrón o la contraseña"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"No se ha podido autenticar"</string>
@@ -1373,7 +1374,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Tocar para desactivar depuración USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar depuración USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para salir, desliza el dedo de arriba abajo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Gira la pantalla para verlo mejor"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Sal de la pantalla dividida para verlo mejor"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abre <xliff:g id="NAME">%s</xliff:g> en pantalla completa para verlo mejor"</string>
<string name="done_label" msgid="7283767013231718521">"Hecho"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control deslizante circular de horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control deslizante circular de minutos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1aeff38..de7665c 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biomeetriline riistvara ei ole saadaval"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentimine tühistati"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tuvastatud"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Nägu ei tuvastatud"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentimine tühistati"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodi, mustrit ega parooli pole määratud"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Viga autentimisel"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Väljumiseks pühkige ülevalt alla."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Selge"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Pöörake parema vaate jaoks"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Parema vaate jaoks väljuge jagatud ekraanikuvast"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Parema vaate jaoks avage rakendus <xliff:g id="NAME">%s</xliff:g> täisekraanil"</string>
<string name="done_label" msgid="7283767013231718521">"Valmis"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ringikujuline tunniliugur"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Ringikujuline minutiliugur"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 293c34f..a07d982 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrikoa ez dago erabilgarri"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Utzi da autentifikazioa"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ez da ezagutu"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ez da ezagutu aurpegia"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Utzi egin da autentifikazioa"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ez da ezarri PIN koderik, eredurik edo pasahitzik"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Errorea autentifikatzean"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Irteteko, pasatu hatza goitik behera."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ados"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Biratu pantaila ikuspegi hobea lortzeko"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Irten pantaila zatitutik ikuspegi hobea lortzeko"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Ireki <xliff:g id="NAME">%s</xliff:g> pantaila osoan eta ikuspegi hobea lortuko duzu"</string>
<string name="done_label" msgid="7283767013231718521">"Eginda"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ordua aukeratzeko ikuspegi zirkularra"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutuak aukeratzeko ikuspegi zirkularra"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 03ee191..bbf5988 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"سختافزار زیستسنجی دردسترس نیست"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"اصالتسنجی لغو شد"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"شناسایی نشد"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"چهره شناسایی نشد"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"اصالتسنجی لغو شد"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"پین، الگو یا گذرواژهای تنظیم نشده است"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خطا هنگام اصالتسنجی"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"متوجه شدم"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"برای دید بهتر، دستگاه را بچرخانید"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"برای دید بهتر، از صفحهٔ دونیمه خارج شوید"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"برای دید بهتر، <xliff:g id="NAME">%s</xliff:g> را بهصورت تمامصفحه باز کنید"</string>
<string name="done_label" msgid="7283767013231718521">"تمام"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"لغزنده دایرهای ساعت"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"لغزنده دایرهای دقیقه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0d755ae..bf866f6 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinen laitteisto ei käytettävissä"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Todennus peruutettu"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tunnistettu"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Kasvoja ei tunnistettu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Todennus peruutettu"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodia, kuviota tai salasanaa ei ole asetettu"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Virhe todennuksessa"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Selvä"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Kierrä, niin saat paremman näkymän"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Poistu jaetulta näytöltä, niin saat paremman näkymän"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Avaa <xliff:g id="NAME">%s</xliff:g>, niin saat paremman näkymän"</string>
<string name="done_label" msgid="7283767013231718521">"Valmis"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Tuntien ympyränmuotoinen liukusäädin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minuuttien ympyränmuotoinen liukusäädin"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 452bbca..0057a08 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Données biométriques non reconnues"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Visage non reconnu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun NIP, schéma ou mot de passe défini"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Pour quitter, balayez vers le bas à partir du haut."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Faire pivoter pour obtenir un meilleur affichage"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Quitter l\'écran partagé pour obtenir un meilleur affichage"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Ouvrir <xliff:g id="NAME">%s</xliff:g> en plein écran pour un meilleur affichage"</string>
<string name="done_label" msgid="7283767013231718521">"Terminé"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Curseur circulaire des heures"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Curseur circulaire des minutes"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 0d1b681..4848eb3 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non reconnue"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Visage non reconnu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun code, schéma ni mot de passe n\'est défini"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Pour quitter, balayez l\'écran du haut vers le bas."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Faites pivoter pour mieux voir"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Quittez l\'écran partagé pour mieux voir"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Ouvrez <xliff:g id="NAME">%s</xliff:g> en plein écran pour mieux voir"</string>
<string name="done_label" msgid="7283767013231718521">"OK"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Curseur circulaire des heures"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Curseur circulaire des minutes"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9095932..e0cf31d 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"O hardware biométrico non está dispoñible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Cancelouse a autenticación"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non se recoñeceu"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Non se recoñeceu a cara"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Cancelouse a autenticación"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non se estableceu ningún PIN, padrón ou contrasinal"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Produciuse un erro ao realizar a autenticación"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para saír, pasa o dedo cara abaixo desde a parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Xira a pantalla para que se vexa mellor"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Sae da pantalla dividida para que se vexa mellor"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abre <xliff:g id="NAME">%s</xliff:g> en pantalla completa para unha mellor visualización"</string>
<string name="done_label" msgid="7283767013231718521">"Feito"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control desprazable circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control desprazable circular dos minutos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 03e1bde..eb99a9d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"પ્રમાણીકરણ રદ કર્યું"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ઓળખાયેલ નથી"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ચહેરો ઓળખાયો નથી"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"પ્રમાણીકરણ રદ કર્યું"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"કોઈ પિન, પૅટર્ન અથવા પાસવર્ડ સેટ કરેલો નથી"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"પ્રમાણિત કરવામાં ભૂલ આવી"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"બહાર નીકળવા માટે, ટોચ પરથી નીચે સ્વાઇપ કરો."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"સમજાઈ ગયું"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"બહેતર વ્યૂ માટે ફેરવો"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"બહેતર વ્યૂ માટે, વિભાજિત સ્ક્રીનમાંથી બહાર નીકળો"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"બહેતર વ્યૂ માટે, પૂર્ણ સ્ક્રીનમાં <xliff:g id="NAME">%s</xliff:g> ખોલો"</string>
<string name="done_label" msgid="7283767013231718521">"થઈ ગયું"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"કલાકનું વર્તુળાકાર સ્લાઇડર"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"મિનિટનું વર્તુળાકાર સ્લાઇડર"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f204de9..e4b57ee 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द किया गया"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"पहचान नहीं हो पाई"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"चेहरा नहीं पहचाना गया"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द किया गया"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"पिन, पैटर्न या पासवर्ड सेट नहीं है"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"गड़बड़ी की पुष्टि की जा रही है"</string>
@@ -1717,7 +1718,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"रंग में सुधार करने की सुविधा"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
- <string name="hearing_aids_feature_name" msgid="1125892105105852542">"सुनने में मदद करने वाले डिवाइस"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"कान की मशीन"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"आवाज़ बटन को छोड़ें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> की सुविधा चालू करने के लिए, आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें."</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहर निकलने के लिए, ऊपर से नीचे स्वाइप करें."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ठीक है"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"बेहतर व्यू पाने के लिए, डिवाइस की स्क्रीन को घुमाएं"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"बेहतर व्यू पाने के लिए, स्प्लिट स्क्रीन मोड बंद करें"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"बेहतर व्यू पाने के लिए <xliff:g id="NAME">%s</xliff:g> को फ़ुल स्क्रीन में खोलें"</string>
<string name="done_label" msgid="7283767013231718521">"हो गया"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"घंटो का चक्राकार स्लाइडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनटों का चक्राकार स्लाइडर"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 78f5b6f..adbacad 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -161,7 +161,7 @@
<string name="httpErrorLookup" msgid="3099834738227549349">"URL nije moguće pronaći."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Shema autentifikacije web-lokacije nije podržana."</string>
<string name="httpErrorAuth" msgid="469553140922938968">"Autentifikacija nije moguća."</string>
- <string name="httpErrorProxyAuth" msgid="7229662162030113406">"Provjera autentičnosti preko proxy poslužitelja nije bila uspješna."</string>
+ <string name="httpErrorProxyAuth" msgid="7229662162030113406">"Autentifikacija preko proxy poslužitelja nije bila uspješna."</string>
<string name="httpErrorConnect" msgid="3295081579893205617">"Povezivanje s poslužiteljem nije moguće."</string>
<string name="httpErrorIO" msgid="3860318696166314490">"Komunikacija s poslužiteljem nije moguća. Pokušajte ponovno kasnije."</string>
<string name="httpErrorTimeout" msgid="7446272815190334204">"Veza s poslužiteljem privremeno je zaustavljena."</string>
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Lice nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nisu postavljeni PIN, uzorak ni zaporka"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Pogreška prilikom autentifikacije"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Za izlaz prijeđite prstom od vrha prema dolje."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Shvaćam"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Zakrenite kako biste bolje vidjeli"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Zatvorite podijeljeni zaslon kako biste bolje vidjeli"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otvorite aplikaciju <xliff:g id="NAME">%s</xliff:g> preko cijelog zaslona za bolji prikaz"</string>
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač sati"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač minuta"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 19a76dc..b9d478f 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrikus hardver nem áll rendelkezésre"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hitelesítés megszakítva"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nem ismerhető fel"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Sikertelen arcfelismerés"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Hitelesítés megszakítva"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nem állított be PIN-kódot, mintát vagy jelszót."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Hiba történt a hitelesítés közben"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Kilépéshez csúsztassa ujját fentről lefelé."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Értem"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Forgassa el a jobb élmény érdekében"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Lépjen ki az osztott képernyős módból a jobb élmény érdekében"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"A jobb élmény érdekében teljes képernyős módban nyissa meg a(z) <xliff:g id="NAME">%s</xliff:g> alkalmazást"</string>
<string name="done_label" msgid="7283767013231718521">"Kész"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Óra kör alakú csúszkája"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Perc kör alakú csúszkája"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index e6adbce..b2dcbc5 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Կենսաչափական սարքը հասանելի չէ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Նույնականացումը չեղարկվեց"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Չհաջողվեց ճանաչել"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Դեմքը չի ճանաչվել"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Նույնականացումը չեղարկվեց"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ավելացրեք PIN կոդ, նախշ կամ գաղտնաբառ։"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Չհաջողվեց նույնականացնել"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Պարզ է"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Պտտեք՝ դիտակերպը լավացնելու համար"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Դուրս եկեք կիսված էկրանի ռեժիմից՝ դիտակերպը լավացնելու համար"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Բացեք <xliff:g id="NAME">%s</xliff:g> հավելվածը լիաէկրան ռեժիմում՝ դիտակերպը լավացնելու համար"</string>
<string name="done_label" msgid="7283767013231718521">"Պատրաստ է"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ժամերի ընտրություն թվատախտակից"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Րոպեների ընտրություն թվատախտակից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index acedbe2..c0aa2f7 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentikasi dibatalkan"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Wajah tidak dikenali"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentikasi dibatalkan"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Tidak ada PIN, pola, atau sandi yang disetel"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error saat mengautentikasi"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Untuk keluar, geser layar ke bawah dari atas."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Mengerti"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Putar posisi layar untuk mendapatkan tampilan yang lebih baik"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Keluar dari layar terpisah untuk mendapatkan tampilan yang lebih baik"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Buka <xliff:g id="NAME">%s</xliff:g> dalam layar penuh untuk mendapatkan tampilan yang lebih baik"</string>
<string name="done_label" msgid="7283767013231718521">"Selesai"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Penggeser putar jam"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Penggeser putar menit"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0df532f..f8dc531 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Lífkennavélbúnaður ekki tiltækur"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hætt við auðkenningu"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Þekktist ekki"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Andlit þekkist ekki"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Hætt við auðkenningu"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ekkert PIN-númer, mynstur eða aðgangsorð stillt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Villa við auðkenningu"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Strjúktu niður frá efri brún til að hætta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ég skil"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Snúðu til að sjá betur"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Lokaðu skjáskiptingu til að sjá betur"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Opnaðu <xliff:g id="NAME">%s</xliff:g> á öllum skjánum til að fá betra yfirlit"</string>
<string name="done_label" msgid="7283767013231718521">"Lokið"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Valskífa fyrir klukkustundir"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Valskífa fyrir mínútur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9ae0ff2..30fd6fb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrico non disponibile"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticazione annullata"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non riconosciuto"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Volto non riconosciuto"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticazione annullata"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non hai impostato PIN, sequenza o password"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Errore durante l\'autenticazione"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Per uscire, scorri dall\'alto verso il basso."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Ruota per migliorare l\'anteprima"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Esci dallo schermo diviso per migliorare l\'anteprima"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Apri <xliff:g id="NAME">%s</xliff:g> a schermo intero per migliorare la visualizzazione"</string>
<string name="done_label" msgid="7283767013231718521">"Fine"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Cursore circolare per le ore"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Cursore circolare per i minuti"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 046d872..a24becd 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"חומרה ביומטרית לא זמינה"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"האימות בוטל"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"לא זוהתה"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"הפנים לא זוהו"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"האימות בוטל"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"עוד לא הוגדרו קוד אימות, קו ביטול נעילה או סיסמה"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"שגיאה באימות"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"כדי לצאת, פשוט מחליקים אצבע מלמעלה למטה."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"הבנתי"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"מסובבים כדי לראות טוב יותר"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"צריך לצאת מהמסך המפוצל כדי לראות טוב יותר"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"צריך לפתוח את <xliff:g id="NAME">%s</xliff:g> במסך מלא כדי לראות טוב יותר"</string>
<string name="done_label" msgid="7283767013231718521">"סיום"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"מחוון שעות מעגלי"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"מחוון דקות מעגלי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ee1fe62..2f71e50 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生体認証ハードウェアが利用できません"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"認証をキャンセルしました"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"認識されませんでした"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"顔を認識できません"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"認証をキャンセルしました"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN、パターン、パスワードが設定されていません"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"エラー認証"</string>
@@ -650,8 +651,8 @@
<string name="fingerprint_error_timeout" msgid="7361192266621252164">"指紋の設定がタイムアウトしました。もう一度お試しください。"</string>
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋の操作をキャンセルしました。"</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"指紋の操作がユーザーによりキャンセルされました。"</string>
- <string name="fingerprint_error_lockout" msgid="6626753679019351368">"試行回数が上限を超えました。代わりに PIN を入力してください。"</string>
- <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"試行回数が上限を超えました。代わりに PIN を入力してください。"</string>
+ <string name="fingerprint_error_lockout" msgid="6626753679019351368">"試行回数が上限を超えました。代わりに画面ロックを使用してください。"</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"試行回数が上限を超えました。代わりに画面ロックを使用してください。"</string>
<string name="fingerprint_error_unable_to_process" msgid="2446280592818621224">"指紋を処理できません。もう一度お試しください。"</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"終了するには、上から下にスワイプします。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"画面を回転させて見やすくしましょう"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"分割画面を終了して見やすくしましょう"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"<xliff:g id="NAME">%s</xliff:g> を全画面表示で開いて見やすくしましょう"</string>
<string name="done_label" msgid="7283767013231718521">"完了"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"円形スライダー(時)"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"円形スライダー(分)"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 0a0a813..3a76bca 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ბიომეტრიული აპარატურა მიუწვდომელია"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ავტორიზაცია გაუქმდა"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"არ არის ამოცნობილი"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"სახის ამოცნობა ვერ მოხერხდა"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ავტორიზაცია გაუქმდა"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-კოდი, ნიმუში ან პაროლი დაყენებული არ არის"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"შეცდომა ავთენტიკაციისას"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"გამოსვლისათვის, გაასრიალეთ ზემოდან ქვემოთ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"გასაგებია"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"შეატრიალეთ უკეთესი ხედისთვის"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"უკეთესი ხედვისთვის გამოდით გაყოფილი ეკრანიდან"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"გახსენით <xliff:g id="NAME">%s</xliff:g> სრულ ეკრანზე უკეთესი ხედისთვის"</string>
<string name="done_label" msgid="7283767013231718521">"დასრულდა"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"საათების წრიული სლაიდერი"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"წუთების წრიული სლაიდერი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 90fa20f..d765aa1 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалық жабдық жоқ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификациядан бас тартылды."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Танылмады"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Бет танылмады."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификациядан бас тартылды."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ешқандай PIN коды, өрнек немесе құпия сөз орнатылмаған."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификациялауда қате шықты."</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Шығу үшін жоғарыдан төмен қарай сырғытыңыз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Түсінікті"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Жақсырақ көру үшін бұрыңыз."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Жақсырақ көру үшін экранды бөлу режимінен шығыңыз."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Жақсырақ көру үшін <xliff:g id="NAME">%s</xliff:g> қолданбасын толық экранда ашыңыз."</string>
<string name="done_label" msgid="7283767013231718521">"Дайын"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Сағаттар айналымының қозғалтқышы"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Минут айналымын қозғалтқыш"</string>
@@ -1945,7 +1946,7 @@
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ұсынылатын аймақтар"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Ұсынылған тілдер"</string>
<string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Ұсынылған аймақтар"</string>
- <string name="language_picker_section_all" msgid="1985809075777564284">"Барлық тілдер"</string>
+ <string name="language_picker_section_all" msgid="1985809075777564284">"Барлық тіл"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Барлық аймақтар"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Іздеу"</string>
<string name="app_suspended_title" msgid="888873445010322650">"Қолданба қолжетімді емес"</string>
@@ -2291,7 +2292,7 @@
<string name="window_magnification_prompt_title" msgid="2876703640772778215">"Жаңа ұлғайту параметрлері"</string>
<string name="window_magnification_prompt_content" msgid="8159173903032344891">"Енді экранның бір бөлігін ұлғайтуға болады."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Параметрлер бөлімінен қосу"</string>
- <string name="dismiss_action" msgid="1728820550388704784">"Қабылдамау"</string>
+ <string name="dismiss_action" msgid="1728820550388704784">"Жабу"</string>
<string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Құрылғы микрофонын блоктан шығарыңыз"</string>
<string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Құрылғы камерасын блоктан шығарыңыз"</string>
<string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"<b><xliff:g id="APP">%s</xliff:g></b> және барлық қолданбалар мен қызметтерге арналған."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 949b32c..72826bb 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"មិនអាចប្រើឧបករណ៍ស្កេនស្នាមម្រាមដៃបានទេ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"មិនអាចសម្គាល់បានទេ"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"មិនស្គាល់មុខ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"គ្មានការកំណត់កូដ pin លំនាំ ឬពាក្យសម្ងាត់ទេ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"មានបញ្ហាក្នុងការផ្ទៀងផ្ទាត់"</string>
@@ -685,7 +686,7 @@
<string name="face_acquired_too_far" msgid="2922278214231064859">"ដាក់ទូរសព្ទឱ្យជិតជាងមុន"</string>
<string name="face_acquired_too_high" msgid="8278815780046368576">"រំកិលទូរសព្ទឡើងលើ"</string>
<string name="face_acquired_too_low" msgid="4075391872960840081">"រំកិលទូរសព្ទចុះក្រោម"</string>
- <string name="face_acquired_too_right" msgid="6245286514593540859">"ដាក់ទូរសព្ទទៅខាងឆ្វេងអ្នក"</string>
+ <string name="face_acquired_too_right" msgid="6245286514593540859">"រំកិលទូរសព្ទទៅខាងឆ្វេង"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"រំកិលទូរសព្ទទៅខាងស្ដាំ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"សូមមើលឱ្យចំឧបករណ៍របស់អ្នកជាងមុន។"</string>
<string name="face_acquired_not_detected" msgid="1057966913397548150">"មើលមិនឃើញមុខរបស់អ្នកទេ។ កាន់ទូរសព្ទរបស់អ្នកដាក់ត្រឹមភ្នែក។"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"យល់ហើយ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"បង្វិលដើម្បីមើលបានកាន់តែច្បាស់"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ចេញពីមុខងារបំបែកអេក្រង់ដើម្បីមើលបានកាន់តែច្បាស់"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"បើក <xliff:g id="NAME">%s</xliff:g> នៅក្នុងអេក្រង់ពេញ ដើម្បីមើលបានកាន់តែច្បាស់"</string>
<string name="done_label" msgid="7283767013231718521">"រួចរាល់"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"គ្រាប់រំកិលរង្វង់ម៉ោង"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"គ្រាប់រំកិលរង្វង់នាទី"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index a72c387..736050e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ಮುಖವನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ಪಿನ್, ಪ್ಯಾಟರ್ನ್ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ಸೆಟ್ ಮಾಡಿಲ್ಲ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ದೃಢೀಕರಿಸುವಾಗ ದೋಷ ಎದುರಾಗಿದೆ"</string>
@@ -1353,7 +1354,7 @@
<string name="time_picker_dialog_title" msgid="9053376764985220821">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"ದಿನಾಂಕವನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="date_time_set" msgid="4603445265164486816">"ಹೊಂದಿಸು"</string>
- <string name="date_time_done" msgid="8363155889402873463">"ಮುಗಿದಿದೆ"</string>
+ <string name="date_time_done" msgid="8363155889402873463">"ಆಯಿತು"</string>
<string name="perms_new_perm_prefix" msgid="6984556020395757087"><font size="12" fgcolor="#ff33b5e5">"ಹೊಸ: "</font></string>
<string name="perms_description_app" msgid="2747752389870161996">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಮೂಲಕ ಒದಗಿಸಲಾಗಿದೆ."</string>
<string name="no_permissions" msgid="5729199278862516390">"ಯಾವುದೇ ಅನುಮತಿಗಳ ಅಗತ್ಯವಿಲ್ಲ"</string>
@@ -1852,8 +1853,8 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ತಿಳಿಯಿತು"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ಅತ್ಯುತ್ತಮ ವೀಕ್ಷಣೆಗಾಗಿ ತಿರುಗಿಸಿ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ಅತ್ಯುತ್ತಮ ವೀಕ್ಷಣೆಗಾಗಿ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ನಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
- <string name="done_label" msgid="7283767013231718521">"ಮುಗಿದಿದೆ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ಅತ್ಯುತ್ತಮ ವೀಕ್ಷಣೆಗಾಗಿ <xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ತೆರೆಯಿರಿ"</string>
+ <string name="done_label" msgid="7283767013231718521">"ಆಯಿತು"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ಗಂಟೆಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
<string name="select_hours" msgid="5982889657313147347">"ಗಂಟೆಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 20de6ab..8aa80e5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"생체 인식 하드웨어를 사용할 수 없음"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"인증이 취소되었습니다."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"인식할 수 없음"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"얼굴을 인식할 수 없습니다."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"인증이 취소되었습니다."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, 패턴, 비밀번호가 설정되지 않음"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"인증 오류"</string>
@@ -637,7 +638,7 @@
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"너무 밝음"</string>
<string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"전원 누름이 감지되었습니다."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"조정 시도"</string>
- <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"지문이 인식될 때마다 손가락을 조금씩 이동하세요"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"지문이 인식될 때마다 손가락의 위치를 조금씩 바꾸세요"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"지문이 인식되지 않았습니다."</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"종료하려면 위에서 아래로 스와이프합니다."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"확인"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"카메라 미리보기 화면이 잘 보이도록 회전하세요."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"카메라 미리보기 화면이 잘 보이도록 화면 분할을 종료하세요."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"화면이 더 잘 보이도록 <xliff:g id="NAME">%s</xliff:g>을(를) 전체 화면에서 여세요."</string>
<string name="done_label" msgid="7283767013231718521">"완료"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"시간 원형 슬라이더"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"분 원형 슬라이더"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 9b10b5b..6b40da6 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Жүз таанылган жок"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN код, графикалык ачкыч же сырсөз коюлган жок"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификация катасы"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Чыгуу үчүн экранды ылдый сүрүп коюңуз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Түшүндүм"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Жакшыраак көрүү үчүн буруңуз"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Жакшыраак көрүү үчүн экранды бөлүү режиминен чыгыңыз"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Жакшыраак көрүү үчүн <xliff:g id="NAME">%s</xliff:g> колдонмосун толук экранда ачыңыз"</string>
<string name="done_label" msgid="7283767013231718521">"Даяр"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Саат жебеси"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Мүнөт жебеси"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d2349cd..f1ec5a7 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ບໍ່ຮັບຮູ້"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ບໍ່ໄດ້ຕັ້ງ PIN, ຮູບແບບປົດລັອກ ຫຼື ລະຫັດຜ່ານ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ເກີດຄວາມຜິດພາດໃນການພິສູດຢືນຢັນ"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ຫາກຕ້ອງການອອກ, ໃຫ້ຮູດຈາກທາງເທິງລົງມາທາງລຸ່ມ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ໄດ້ແລ້ວ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ໝຸນເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ອອກຈາກແບ່ງໜ້າຈໍເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ເປີດ <xliff:g id="NAME">%s</xliff:g> ໃນໂໝດເຕັມຈໍເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>
<string name="done_label" msgid="7283767013231718521">"ແລ້ວໆ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ໂຕໝຸນປັບຊົ່ວໂມງ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ໂຕໝຸນປັບນາທີ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ebcc8bc..677e3d0 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinė aparatinė įranga nepasiekiama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikavimas atšauktas"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Neatpažinta"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Veidas neatpažintas"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikavimas atšauktas"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenustatytas PIN kodas, atrakinimo piešinys arba slaptažodis"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikuojant įvyko klaida"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Supratau"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Pasukite, kad geriau matytumėte vaizdą"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Išeikite iš išskaidyto ekrano režimo, kad geriau matytumėte vaizdą"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Atidarykite „<xliff:g id="NAME">%s</xliff:g>“ viso ekrano režimu, kad geriau matytumėte vaizdą"</string>
<string name="done_label" msgid="7283767013231718521">"Atlikta"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Apskritas valandų šliaužiklis"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Apskritas minučių šliaužiklis"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5edbf88..5d94cc1 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisko datu aparatūra nav pieejama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikācija ir atcelta"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Dati nav atpazīti"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Seja netika atpazīta"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikācija ir atcelta"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, kombinācija vai parole nav iestatīta"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikācijas kļūda"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Lai izietu, no augšdaļas velciet lejup."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Labi"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Lai uzlabotu skatu, pagrieziet ekrānu."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Lai uzlabotu skatu, izejiet no ekrāna sadalīšanas režīma."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Labākam skatam atveriet lietotni <xliff:g id="NAME">%s</xliff:g> pilnekrāna režīmā."</string>
<string name="done_label" msgid="7283767013231718521">"Gatavs"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Stundu apļveida slīdnis"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minūšu apļveida slīdnis"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index acaea7e28..847fee6 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрискиот хардвер е недостапен"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Проверката е откажана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Непознат"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ликот не е препознаен"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Проверката е откажана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не е поставен PIN, шема или лозинка"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при проверката"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"За да излезете, повлечете одозгора надолу."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Сфатив"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Ротирајте за подобар приказ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"За подобар приказ, излезете од поделениот екран"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"За подобар приказ, отворете ја апликацијата <xliff:g id="NAME">%s</xliff:g> на цел екран"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Приказ на часови во кружно движење"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Приказ на минути во кружно движење"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index f1e234a..40578a7 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ബയോമെട്രിക് ഹാർഡ്വെയർ ലഭ്യമല്ല"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"തിരിച്ചറിഞ്ഞില്ല"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"മുഖം തിരിച്ചറിഞ്ഞിട്ടില്ല"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"പിന്നോ പാറ്റേണോ പാസ്വേഡോ സജ്ജീകരിച്ചിട്ടില്ല"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"പിശക് പരിശോധിച്ചുറപ്പിക്കുന്നു"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"അവസാനിപ്പിക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പ് ചെയ്യുക."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"മനസ്സിലായി"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"മികച്ച കാഴ്ചയ്ക്കായി റൊട്ടേറ്റ് ചെയ്യുക"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"മികച്ച കാഴ്ചയ്ക്കായി സ്ക്രീൻ വിഭജന മോഡിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"മികച്ച കാഴ്ചയ്ക്ക് പൂർണ്ണ സ്ക്രീനിൽ <xliff:g id="NAME">%s</xliff:g> തുറക്കുക"</string>
<string name="done_label" msgid="7283767013231718521">"പൂർത്തിയാക്കി"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ചാക്രികമായി മണിക്കൂറുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index e354c9e..eb995cf 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрийн техник хангамж боломжгүй байна"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Нотолгоог цуцаллаа"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таниагүй"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Царайг таньсангүй"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Нотолгоог цуцаллаа"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Тохируулсан пин, хээ эсвэл нууц үг алга"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Баталгаажуулахад алдаа гарлаа"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ойлголоо"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Харагдах байдлыг сайжруулах бол эргүүлнэ үү"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Харагдах байдлыг сайжруулах бол дэлгэцийг хуваах горимоос гарна уу"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Харагдах байдлыг сайжруулах бол <xliff:g id="NAME">%s</xliff:g>-г бүтэн дэлгэцээр нээнэ үү"</string>
<string name="done_label" msgid="7283767013231718521">"Дууссан"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Цаг гүйлгэгч"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Минут гүйлгэгч"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 003d290..2b40d39 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ऑथेंटिकेशन रद्द केले"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ओळखले नाही"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"चेहरा ओळखता आला नाही"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ऑथेंटिकेशन रद्द केले"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कोणताही पिन, पॅटर्न किंवा पासवर्ड सेट केलेला नाही"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"एरर ऑथेंटिकेट करत आहे"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"समजले"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"अधिक चांगल्या दृश्यासाठी फिरवा"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"अधिक चांगल्या दृश्यासाठी स्प्लिट स्क्रीनमधून बाहेर पडा"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"अधिक चांगल्या दृश्यासाठी <xliff:g id="NAME">%s</xliff:g> हे फुल स्क्रीनमध्ये उघडा"</string>
<string name="done_label" msgid="7283767013231718521">"पूर्ण झाले"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"तास परिपत्रक स्लायडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनिटे परिपत्रक स्लायडर"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a744aa9..7aeb96e 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Perkakasan biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Pengesahan dibatalkan"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Wajah tidak dikenali"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Pengesahan dibatalkan"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, corak atau kata laluan tidak ditetapkan"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ralat semasa membuat pengesahan"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Untuk keluar, leret dari atas ke bawah."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Faham"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Putar untuk mendapatkan paparan yang lebih baik"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Keluar daripada skrin pisah untuk mendapatkan paparan yang lebih baik"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Buka <xliff:g id="NAME">%s</xliff:g> dalam skrin penuh untuk mendapatkan paparan yang lebih baik"</string>
<string name="done_label" msgid="7283767013231718521">"Selesai"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Penggelangsar bulatan jam"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Penggelangsar bulatan minit"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index b028f5f..1fdcb14 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -199,7 +199,7 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"အာရုံခံကိရိယာ အကြောင်းကြားချက် ဝန်ဆောင်မှု"</string>
<string name="twilight_service" msgid="8964898045693187224">"နေဝင်ဆည်းဆာ ဝန်ဆောင်မှု"</string>
<string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS အချိန်အပ်ဒိတ် ဝန်ဆောင်မှု"</string>
- <string name="device_policy_manager_service" msgid="5085762851388850332">"ကိရိယာဆိုင်ရာ မူဝါဒ မန်နေဂျာဝန်ဆောင်မှု"</string>
+ <string name="device_policy_manager_service" msgid="5085762851388850332">"ကိရိယာ မူဝါဒ မန်နေဂျာဝန်ဆောင်မှု"</string>
<string name="music_recognition_manager_service" msgid="7481956037950276359">"တေးဂီတကို သိရှိမှတ်မိခြင်း စီမံခန့်ခွဲမှုစနစ် ဝန်ဆောင်မှု"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"စက်စီမံအက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"မသိ"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"မျက်နှာကို မသိရှိပါ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ပင်နံပါတ်၊ လော့ခ်ပုံစံ သို့မဟုတ် စကားဝှက် သတ်မှတ်မထားပါ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"အထောက်အထားစိစစ်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ထွက်ရန် အပေါ်မှ အောက်သို့ ဆွဲချပါ။"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ရပါပြီ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ပိုကောင်းသောမြင်ကွင်းအတွက် လှည့်ပါ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ပိုကောင်းသောမြင်ကွင်းအတွက် မျက်နှာပြင် ခွဲ၍ပြသခြင်းမှ ထွက်ပါ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ပိုကောင်းသောမြင်ကွင်းအတွက် ဖန်သားပြင်အပြည့်ဖြင့် <xliff:g id="NAME">%s</xliff:g> ကို ဖွင့်ပါ"</string>
<string name="done_label" msgid="7283767013231718521">"ပြီးပါပြီ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"နာရီရွေးချက်စရာ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8976b87..dec5664 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvare er utilgjengelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen er avbrutt"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke gjenkjent"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Gjenkjenner ikke ansiktet"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen er avbrutt"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-kode, mønster eller passord er ikke angitt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Feil under autentiseringen"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Sveip ned fra toppen for å avslutte."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Skjønner"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Roter for å få en bedre visning"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Avslutt delt skjerm for å få en bedre visning"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Åpne <xliff:g id="NAME">%s</xliff:g> i fullskjerm for å se bedre"</string>
<string name="done_label" msgid="7283767013231718521">"Ferdig"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Sirkulær glidebryter for timer"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Sirkulær glidebryter for minutter"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 475abe5..716ad02 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -89,8 +89,8 @@
<string name="notification_channel_call_forward" msgid="8230490317314272406">"कल फर्वार्ड गर्ने सेवा"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"आपत्कालीन कलब्याक मोड"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"मोबाइल डेटाको स्थिति"</string>
- <string name="notification_channel_sms" msgid="1243384981025535724">"SMS सन्देशहरू"</string>
- <string name="notification_channel_voice_mail" msgid="8457433203106654172">"भ्वाइस मेल सन्देशहरू"</string>
+ <string name="notification_channel_sms" msgid="1243384981025535724">"SMS म्यासेजहरू"</string>
+ <string name="notification_channel_voice_mail" msgid="8457433203106654172">"भ्वाइस मेल म्यासेजहरू"</string>
<string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi कल"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"SIM को स्थिति"</string>
<string name="notification_channel_sim_high_prio" msgid="642361929452850928">"उच्च प्राथमिकता रहेको SIM को स्थिति"</string>
@@ -122,7 +122,7 @@
<string name="roamingTextSearching" msgid="5323235489657753486">"सेवाको खोजी गर्दै…"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"Wi-Fi कलिङ सेटअप गर्न सकिएन"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"Wi-Fi मार्फत कलहरू गर्न र सन्देशहरू पठाउन सबभन्दा पहिला आफ्नो सेवा प्रदायकलाई यो सेवा सेट गर्न भन्नुहोस्। त्यसपछि सेटिङहरूबाट Wi-Fi कलिङलाई सक्रिय पार्नुहोस्। (त्रुटिसम्बन्धी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"Wi-Fi मार्फत कलहरू गर्न र म्यासेजहरू पठाउन सबभन्दा पहिला आफ्नो सेवा प्रदायकलाई यो सेवा सेट गर्न भन्नुहोस्। त्यसपछि सेटिङहरूबाट Wi-Fi कलिङलाई सक्रिय पार्नुहोस्। (त्रुटिसम्बन्धी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"तपाईंको सेवा प्रदायकमार्फत Wi-Fi कलिङ सुविधा दर्ता गर्ने क्रममा देखिएको समस्या: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -275,8 +275,8 @@
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"कार मोड"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"खाताको स्थिति"</string>
- <string name="notification_channel_developer" msgid="1691059964407549150">"विकासकर्ताका सन्देशहरू"</string>
- <string name="notification_channel_developer_important" msgid="7197281908918789589">"विकासकर्तासम्बन्धी महत्त्वपूर्ण सन्देशहरू"</string>
+ <string name="notification_channel_developer" msgid="1691059964407549150">"विकासकर्ताका म्यासेजहरू"</string>
+ <string name="notification_channel_developer_important" msgid="7197281908918789589">"विकासकर्तासम्बन्धी महत्त्वपूर्ण म्यासेजहरू"</string>
<string name="notification_channel_updates" msgid="7907863984825495278">"अद्यावधिकहरू"</string>
<string name="notification_channel_network_status" msgid="2127687368725272809">"नेटवर्कको स्थिति"</string>
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"नेटवर्कका अलर्टहरू"</string>
@@ -300,14 +300,14 @@
<string name="managed_profile_label" msgid="7316778766973512382">"कार्य प्रोफाइलमा बदल्नुहोस्"</string>
<string name="user_owner_app_label" msgid="1553595155465750298">"<xliff:g id="APP_NAME">%1$s</xliff:g> को व्यक्तिगत प्रोफाइल प्रयोग गर्नुहोस्"</string>
<string name="managed_profile_app_label" msgid="367401088383965725">"<xliff:g id="APP_NAME">%1$s</xliff:g> को कार्य प्रोफाइल प्रयोग गर्नुहोस्"</string>
- <string name="permgrouplab_contacts" msgid="4254143639307316920">"सम्पर्कहरू"</string>
+ <string name="permgrouplab_contacts" msgid="4254143639307316920">"कन्ट्याक्टहरू"</string>
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"तपाईँको सम्पर्कमाथि पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"लोकेसन"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"यस डिभाइसको स्थानमाथि पहुँच"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"पात्रो"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"तपाईंको पात्रोमाथि पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
+ <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS म्यासेजहरू पठाउनुहोस् र हेर्नुहोस्"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"फाइलहरू"</string>
<string name="permgroupdesc_storage" msgid="5378659041354582769">"आफ्नो डिभाइसमा रहेका फाइलहरू हेर्नुहोस् र प्रयोग गर्नुहोस्"</string>
<string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"सङ्गीत तथा अडियो"</string>
@@ -362,25 +362,25 @@
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"फोन कलहरूको जवाफ दिनुहोस्"</string>
<string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"एपलाई आगमन फोन कलको जवाफ दिन अनुमति दिन्छ।"</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"टेक्स्ट म्यासेजहरू (SMS) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"एपलाई SMS सन्देशहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"एपलाई SMS म्यासेजहरू प्राप्त गर्न र प्रक्रिया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको म्यासेजहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"टेक्स्ट म्यासेज (MMS) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"एपलाई MMS सन्देशहरू प्राप्त गर्न र प्रकृया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको सन्देशहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
- <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"मोबाइल प्रसारणसम्बन्धी सन्देशहरू फर्वार्ड गर्नुहोस्"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी सन्देशहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले एपलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक एपहरूले आपत्कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"एपलाई MMS म्यासेजहरू प्राप्त गर्न र प्रकृया गर्न अनुमति दिन्छ। यसको मतलब अनुप्रयोगले तपाईंको उपकरणमा पठाइएको म्यासेजहरू तपाईंलाई नदेखाईनै मोनिटर गर्न वा मेटाउन सक्दछ।"</string>
+ <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"मोबाइल प्रसारणसम्बन्धी म्यासेजहरू फर्वार्ड गर्नुहोस्"</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी म्यासेजहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले एपलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक एपहरूले आपत्कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"जारी रहेका कलहरू व्यवस्थापन गर्न"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"तपाईं यो एपलाई अनुमति दिनुभयो यस एपले तपाईंको डिभाइसमा जारी रहेका कलसम्बन्धी विवरण हेर्न र ती कलहरू नियन्त्रण गर्न सक्छ।"</string>
- <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारित सन्देशहरू पढ्नुहोस्"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण सन्देशहरू एपलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपत्कालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब एपहरूले एउटा आपत्कालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
+ <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारित म्यासेजहरू पढ्नुहोस्"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण म्यासेजहरू एपलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपत्कालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब एपहरूले एउटा आपत्कालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्य बनाइका फिडहरू पढ्नुहोस्"</string>
<string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"एपलाई अहिलेको समीकरण गरिएका सूचकहरू बारे विवरणहरू लिने अनुमति दिन्छ।"</string>
- <string name="permlab_sendSms" msgid="7757368721742014252">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
- <string name="permdesc_sendSms" msgid="6757089798435130769">"एपलाई SMS सन्देशहरू पठाउन अनुमति दिन्छ। यसले अप्रत्यासित चार्जहरूको परिणाम दिन सक्दछ। खराब एपहरूले तपाईंको पुष्टि बिना सन्देशहरू पठाएर तपाईंको पैसा खर्च गराउन सक्दछ।"</string>
+ <string name="permlab_sendSms" msgid="7757368721742014252">"SMS म्यासेजहरू पठाउनुहोस् र हेर्नुहोस्"</string>
+ <string name="permdesc_sendSms" msgid="6757089798435130769">"एपलाई SMS म्यासेजहरू पठाउन अनुमति दिन्छ। यसले अप्रत्यासित चार्जहरूको परिणाम दिन सक्दछ। खराब एपहरूले तपाईंको पुष्टि बिना म्यासेजहरू पठाएर तपाईंको पैसा खर्च गराउन सक्दछ।"</string>
<string name="permlab_readSms" msgid="5164176626258800297">"तपाईंका टेक्स्ट म्यासेजहरू (SMS वा MMS) पढ्नुहोस्"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"यस एपले तपाईंको ट्याब्लेटमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
- <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"यस एपले तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका सबै SMS.(पाठ) सन्देशहरू पढ्न सक्छ।"</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"यस एपले तपाईंको फोनमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"यस एपले तपाईंको ट्याब्लेटमा भण्डारण गरिएका सबै SMS (पाठ) म्यासेजहरू पढ्न सक्छ।"</string>
+ <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"यस एपले तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका सबै SMS.(पाठ) म्यासेजहरू पढ्न सक्छ।"</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"यस एपले तपाईंको फोनमा भण्डारण गरिएका सबै SMS (पाठ) म्यासेजहरू पढ्न सक्छ।"</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"टेक्स्ट म्यासेजहरू (WAP) प्राप्त गर्नुहोस्"</string>
- <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP सन्देशहरू प्राप्त गर्न र प्रशोधन गर्न एपलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका म्यासेजहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>
+ <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP म्यासेजहरू प्राप्त गर्न र प्रशोधन गर्न एपलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका म्यासेजहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"चलिरहेका एपहरू पुनःबहाली गर्नुहोस्"</string>
<string name="permdesc_getTasks" msgid="7388138607018233726">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न एपलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन एपलाई अनुमति दिन सक्छ।"</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"प्रोफाइल र यन्त्र मालिकहरूको व्यवस्थापन गराउनुहोस्"</string>
@@ -470,9 +470,9 @@
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"यस एपले तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका पात्रोसम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"यस एपले तपाईंको फोनमा भण्डारण गरिएका पात्रो सम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"पात्रो घटनाहरू थप्नुहोस् वा परिमार्जन गर्नुहोस् र मालिकको ज्ञान बिना नै पाहुनाहरूलाई इमेल पठाउनुहोस्"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"यस एपले तपाईंको ट्याब्लेटमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"यस एपले तपाईंको Android टिभी डिभाइसमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरूले पठाएको जस्तै देखिने सन्देशहरू पठाउन वा कार्यक्रमका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"यस एपले तपाईंको फोनमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"यस एपले तपाईंको ट्याब्लेटमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने म्यासेजहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"यस एपले तपाईंको Android टिभी डिभाइसमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरूले पठाएको जस्तै देखिने म्यासेजहरू पठाउन वा कार्यक्रमका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"यस एपले तपाईंको फोनमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस एपले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने म्यासेजहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"एपलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो एपलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"अग्रभूमिमा मात्र सटीक स्थानमाथि पहुँच राख्नुहोस्"</string>
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"पहिचान भएन"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"अनुहार पहिचान गर्न सकिएन"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द गरियो"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कुनै पनि PIN, ढाँचा वा पासवर्ड सेट गरिएको छैन"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"प्रमाणित गर्ने क्रममा त्रुटि भयो"</string>
@@ -1145,7 +1146,7 @@
<string name="selectAll" msgid="1532369154488982046">"सबैलाई चयन गर्नुहोस्"</string>
<string name="cut" msgid="2561199725874745819">"काट्नुहोस्"</string>
<string name="copy" msgid="5472512047143665218">"कपी गर्नुहोस्"</string>
- <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"क्लिपबोर्डमा प्रतिलिपि गर्न सकिएन"</string>
+ <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"क्लिपबोर्डमा कपी गर्न सकिएन"</string>
<string name="paste" msgid="461843306215520225">"टाँस्नुहोस्"</string>
<string name="paste_as_plain_text" msgid="7664800665823182587">"सामान्य पाठको रूपमा टाँस्नुहोस्"</string>
<string name="replace" msgid="7842675434546657444">"विस्थापन गर्नुहोस्…"</string>
@@ -1325,8 +1326,8 @@
<string name="accept" msgid="5447154347815825107">"स्वीकार्नुहोस्"</string>
<string name="decline" msgid="6490507610282145874">"अस्वीकार गर्नुहोस्"</string>
<string name="select_character" msgid="3352797107930786979">"अक्षरहरू प्रवेश गराउनुहोस्"</string>
- <string name="sms_control_title" msgid="4748684259903148341">"SMS सन्देशहरू पठाइँदै"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ले धरै संख्यामा SMS सन्देशहरू पठाउँदैछ। के तपाईं यस एपलाई सन्देशहरू पठाउन सुचारु गर्न अनुमति दिन चाहनु हुन्छ?"</string>
+ <string name="sms_control_title" msgid="4748684259903148341">"SMS म्यासेजहरू पठाइँदै"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ले धरै संख्यामा SMS म्यासेजहरू पठाउँदैछ। के तपाईं यस एपलाई म्यासेजहरू पठाउन सुचारु गर्न अनुमति दिन चाहनु हुन्छ?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"अनुमति दिनुहोस्"</string>
<string name="sms_control_no" msgid="4845717880040355570">"अस्वीकार गर्नुहोस्"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> के तपाईं सन्देश पठाउन चाहुनु हुन्छ <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
@@ -1515,7 +1516,7 @@
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्राइभिङ अनुप्रयोगबाट बाहिर निस्कन ट्याप गर्नुहोस्।"</string>
<string name="back_button_label" msgid="4078224038025043387">"पछाडि"</string>
<string name="next_button_label" msgid="6040209156399907780">"अर्को"</string>
- <string name="skip_button_label" msgid="3566599811326688389">"छोड्नुहोस्"</string>
+ <string name="skip_button_label" msgid="3566599811326688389">"स्किप गर्नुहोस्"</string>
<string name="no_matches" msgid="6472699895759164599">"कुनै मिलेन"</string>
<string name="find_on_page" msgid="5400537367077438198">"पृष्ठमा फेला पार्नुहोस्"</string>
<string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# वटा मिल्दोजुल्दो परिणाम}other{{total} मध्ये # वटा मिल्दाजुल्दा परिणाम}}"</string>
@@ -1652,8 +1653,8 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"SIM PIN हाल्नुहोस्"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"PIN हाल्नुहोस्"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"पासवर्ड प्रविष्टि गर्नुहोस्"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM कार्ड अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड प्रविष्टि गर्नुहोस्। विवरणको लागि वाहकलाई सम्पर्क गर्नुहोस्।"</string>
- <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"इच्छित PIN कोड प्रविष्टि गर्नुहोस्"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM कार्ड अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड हाल्नुहोस्। विवरणको लागि वाहकलाई सम्पर्क गर्नुहोस्।"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"इच्छित PIN कोड हाल्नुहोस्"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"मनपर्दो PIN कोड निश्चित गर्नुहोस्"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="5743634657721110967">"SIM कार्ड अनलक गरिँदै छ…"</string>
<string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"गलत PIN कोड।"</string>
@@ -1717,7 +1718,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"रङ सच्याउने सुविधा"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string>
- <string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवण यन्त्रहरू"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"भोल्युम बटनहरू थिच्न छाड्नुहोस्। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन गर्न दुवै भोल्युम बटन फेरि ३ सेकेन्डसम्म थिचिराख्नुहोस्।"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"बुझेँ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"अझ राम्रो दृश्य हेर्न चाहनुहुन्छ भने रोटेट गर्नुहोस्"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"अझ राम्रो दृश्य हेर्न चाहनुहुन्छ भने \"स्प्लिट स्क्रिन\" बाट बाहिरिनुहोस्"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"अझ राम्रो दृश्य हेर्न चाहनुहुन्छ भने <xliff:g id="NAME">%s</xliff:g> खोल्नुहोस्"</string>
<string name="done_label" msgid="7283767013231718521">"भयो"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"घन्टा गोलाकार स्लाइडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनेट गोलाकार स्लाइडर"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1a15c81..7eb3448 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische hardware niet beschikbaar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Verificatie geannuleerd"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Niet herkend"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Gezicht niet herkend"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Verificatie geannuleerd"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen pincode, patroon of wachtwoord ingesteld"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Fout bij verificatie"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Swipe omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ik snap het"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Draai voor een betere weergave"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Sluit het gesplitste scherm voor een betere weergave"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Open <xliff:g id="NAME">%s</xliff:g> op volledig scherm voor een betere weergave"</string>
<string name="done_label" msgid="7283767013231718521">"Klaar"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ronde schuifregelaar voor uren"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Ronde schuifregelaar voor minuten"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 24549569..4d02fb5 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ବାୟୋମେଟ୍ରିକ୍ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ଫେସ ଚିହ୍ନଟ କରାଯାଇନାହିଁ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"କୌଣସି ପିନ୍, ପେଟେର୍ନ ବା ପାସ୍ୱର୍ଡ ସେଟ୍ ନାହିଁ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ପ୍ରାମାଣିକରଣ କରିବା ସମୟରେ ତ୍ରୁଟି"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ବାହାରିବା ପାଇଁ, ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଗଲି"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ଏକ ଭଲ ଭ୍ୟୁ ପାଇଁ ରୋଟେଟ କରନ୍ତୁ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ଏକ ଭଲ ଭ୍ୟୁ ପାଇଁ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ଏକ ଭଲ ଭ୍ୟୁ ପାଇଁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନରେ <xliff:g id="NAME">%s</xliff:g> ଖୋଲନ୍ତୁ"</string>
<string name="done_label" msgid="7283767013231718521">"ହୋଇଗଲା"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ଘଣ୍ଟା ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ମିନିଟ୍ସ ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 233b03d..e9fa2ba 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -191,7 +191,7 @@
<string name="network_logging_notification_title" msgid="554983187553845004">"ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਨ ਅਧੀਨ ਹੈ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="location_changed_notification_title" msgid="3620158742816699316">"ਐਪਾਂ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string>
- <string name="location_changed_notification_text" msgid="7158423339982706912">"ਹੋਰ ਜਾਣਨ ਲਈ ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
+ <string name="location_changed_notification_text" msgid="7158423339982706912">"ਹੋਰ ਜਾਣਨ ਲਈ ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ"</string>
<string name="geofencing_service" msgid="3826902410740315456">"ਭੂਗੋਲਿਕ-ਘੇਰੇ ਸੰਬੰਧੀ ਸੇਵਾ"</string>
<string name="country_detector" msgid="7023275114706088854">"ਦੇਸ਼ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਸੁਵਿਧਾ"</string>
<string name="location_service" msgid="2439187616018455546">"ਟਿਕਾਣਾ ਸੇਵਾ"</string>
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ਕੋਈ ਪਿੰਨ, ਪੈਟਰਨ ਜਾਂ ਪਾਸਵਰਡ ਸੈੱਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ਗੜਬੜ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
@@ -637,7 +638,7 @@
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ"</string>
<string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"ਪਾਵਰ ਬਟਨ ਦਬਾਏ ਜਾਣ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ਵਿਵਸਥਿਤ ਕਰਕੇ ਦੇਖੋ"</string>
- <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ਹਰ ਵਾਰ ਆਪਣੀ ਉਂਗਲ ਨੂੰ ਥੋੜ੍ਹਾ ਹਿਲਾਓ"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ਹਰ ਵਾਰ ਆਪਣੀ ਉਂਗਲੀ ਦੀ ਸਥਿਤੀ ਨੂੰ ਥੋੜਾ ਜਿਹਾ ਬਦਲੋ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ਬਾਹਰ ਜਾਣ ਲਈ, ਉਪਰੋਂ ਹੇਠਾਂ ਸਵਾਈਪ ਕਰੋ।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ਸਮਝ ਲਿਆ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ਬਿਹਤਰ ਦ੍ਰਿਸ਼ ਅਨੁਭਵ ਲਈ ਘੁਮਾਓ"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ਬਿਹਤਰ ਦ੍ਰਿਸ਼ ਅਨੁਭਵ ਲਈ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਤੋਂ ਬਾਹਰ ਆਓ"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ਬਿਹਤਰ ਦ੍ਰਿਸ਼ ਅਨੁਭਵ ਲਈ <xliff:g id="NAME">%s</xliff:g> ਨੂੰ ਪੂਰੀ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਖੋਲ੍ਹੋ"</string>
<string name="done_label" msgid="7283767013231718521">"ਹੋ ਗਿਆ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ਘੰਟੇ ਸਰਕੁਲਰ ਸਲਾਈਡਰ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ਮਿੰਟ ਸਰਕੁਲਰ ਸਲਾਈਡਰ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 587a6d6..1f93f8e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Sprzęt biometryczny niedostępny"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Anulowano uwierzytelnianie"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nie rozpoznano"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Nie rozpoznano twarzy"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Anulowano uwierzytelnianie"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie ustawiono kodu PIN, wzoru ani hasła"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Podczas uwierzytelniania wystąpił błąd"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Aby wyjść, przesuń palcem z góry na dół."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Obróć, aby lepiej widzieć"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Zamknij podzielony ekran, aby lepiej widzieć"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otwórz aplikację <xliff:g id="NAME">%s</xliff:g> na pełnym ekranie, aby lepiej widzieć"</string>
<string name="done_label" msgid="7283767013231718521">"Gotowe"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kołowy suwak godzin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kołowy suwak minut"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c250a6a..fa830a6 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -623,13 +623,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Rosto não reconhecido"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pressione o sensor com firmeza"</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Não foi possível reconhecer a impressão digital. Tente de novo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impressão digital não reconhecida. Tente de novo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressão digital e tente novamente"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pressione o sensor com firmeza"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize de cima para baixo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendi"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Gire a tela para ter uma visualização melhor"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Saia da tela dividida para ter uma visualização melhor"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abra o app <xliff:g id="NAME">%s</xliff:g> em tela cheia para ter uma melhor visualização"</string>
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controle deslizante circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controle deslizante circular dos minutos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 84b5de1..e9c1056 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -623,13 +623,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido."</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Rosto não reconhecido"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou palavra-passe definidos."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro ao autenticar."</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar o bloqueio de ecrã"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduza o bloqueio de ecrã para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Prima firmemente o sensor"</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Não é possível reconhecer a impressão digital. Tente novamente."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impossível reconhecer impressão digital. Volte a tentar."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressões digitais e tente novamente"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Prima firmemente o sensor"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rode para uma melhor visualização"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Saia do ecrã dividido para uma melhor visualização"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abra <xliff:g id="NAME">%s</xliff:g> em ecrã inteiro para uma melhor visualização"</string>
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controlo de deslize circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controlo de deslize circular dos minutos"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c250a6a..fa830a6 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -623,13 +623,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Rosto não reconhecido"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string>
<string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pressione o sensor com firmeza"</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Não foi possível reconhecer a impressão digital. Tente de novo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impressão digital não reconhecida. Tente de novo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressão digital e tente novamente"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pressione o sensor com firmeza"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize de cima para baixo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendi"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Gire a tela para ter uma visualização melhor"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Saia da tela dividida para ter uma visualização melhor"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Abra o app <xliff:g id="NAME">%s</xliff:g> em tela cheia para ter uma melhor visualização"</string>
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controle deslizante circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controle deslizante circular dos minutos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 72877fe..9f55272 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -623,6 +623,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometric indisponibil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentificarea a fost anulată"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nu este recunoscut"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Fața nu a fost recunoscută"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentificarea a fost anulată"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nu este setat un cod PIN, un model sau o parolă"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Eroare la autentificare"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Pentru a ieși, glisează de sus în jos."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Am înțeles"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotește pentru o previzualizare mai bună"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Ieși din ecranul împărțit pentru o previzualizare mai bună"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Deschide <xliff:g id="NAME">%s</xliff:g> pe ecran complet pentru o imagine mai bună"</string>
<string name="done_label" msgid="7283767013231718521">"Terminat"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Selector circular pentru ore"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Selector circular pentru minute"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d592dfa..c0f6095 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -624,13 +624,14 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрическое оборудование недоступно"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификация отменена"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не распознано"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Лицо не распознано."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификация отменена"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Укажите PIN-код, пароль или графический ключ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ошибка аутентификации."</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Использовать блокировку экрана"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Чтобы продолжить, разблокируйте экран."</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Плотно прижмите палец к сканеру."</string>
- <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не удалось распознать отпечаток пальца. Повторите попытку."</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Плотно прижмите палец к сканеру"</string>
+ <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не удалось распознать отпечаток. Повторите попытку."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Очистите сканер отпечатков пальцев и повторите попытку."</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Очистите сканер и повторите попытку."</string>
<string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Плотно прижмите палец к сканеру."</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Чтобы выйти, проведите по экрану сверху вниз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ОК"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Поверните, чтобы лучше видеть."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Выйдите из режима разделения экрана, чтобы лучше видеть."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Откройте приложение \"<xliff:g id="NAME">%s</xliff:g>\" в полноэкранном режиме, чтобы лучше видеть."</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Выбор часов на циферблате"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Выбор минут на циферблате"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index dac899b..ff4aa77 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"සත්යාපනය අවලංගු කළා"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"හඳුනා නොගන්නා ලදී"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"මුහුණ හඳුනා නොගන්නා ලදි"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"සත්යාපනය අවලංගු කළා"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"රහස් අංක, රටා, හෝ මුරපද කිසිවක් සකසා නැත"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"සත්යාපනය කිරීමේ දෝෂයකි"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"වැටහුණි"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"වඩා හොඳ දසුනක් සඳහා කරකවන්න"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"වඩා හොඳ දර්ශනයක් සඳහා බෙදුම් තිරයෙන් පිටවන්න"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"වඩා හොඳ දසුනක් සඳහා <xliff:g id="NAME">%s</xliff:g> පූර්ණ තිරයේ විවෘත කරන්න"</string>
<string name="done_label" msgid="7283767013231718521">"අවසන්"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"පැය කවාකාර සර්පනය"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"මිනිත්තු කවාකාර සර්පනය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 04894f3..791039a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardvér nie je k dispozícii"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Overenie bolo zrušené"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznané"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Tvár nebola rozpoznaná"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Overenie bolo zrušené"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie je nastavený PIN, vzor ani heslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Chyba overenia"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Ukončíte potiahnutím zhora nadol."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Dobre"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Otočte zariadenie pre lepšie zobrazenie"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Ukončite rozdelenú obrazovku pre lepšie zobrazenie"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Otvorte <xliff:g id="NAME">%s</xliff:g> na celej obrazovke pre lepšie zobrazenie"</string>
<string name="done_label" msgid="7283767013231718521">"Hotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kruhový posúvač hodín"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kruhový posúvač minút"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4dd5935..62f6b0c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Strojna oprema za biometrične podatke ni na voljo"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Preverjanje pristnosti je preklicano"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ni prepoznano"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Obraz ni prepoznan"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Preverjanje pristnosti je preklicano"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nastavljena ni nobena koda PIN, vzorec ali geslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Napaka pri preverjanju pristnosti"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Zaprete ga tako, da z vrha s prstom povlečete navzdol."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Razumem"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Zasukajte za boljši pregled."</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Zaprite razdeljeni zaslon za boljši pregled."</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Aplikacijo <xliff:g id="NAME">%s</xliff:g> odprite v celozaslonskem načinu za boljši pregled."</string>
<string name="done_label" msgid="7283767013231718521">"Dokončano"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Okrogli drsnik za ure"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Okrogli drsnik za minute"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index bb0e700..141a94f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Nuk ofrohet harduer biometrik"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Vërtetimi u anulua"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nuk njihet"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Fytyra nuk njihet"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Vërtetimi u anulua"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nuk është vendosur kod PIN, motiv ose fjalëkalim"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Gabim gjatë vërtetimit"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Për të dalë, rrëshqit nga lart poshtë."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"E kuptova"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rrotullo për një pamje më të mirë"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Dil nga ekrani i ndarë për një pamje më të mirë"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Hape <xliff:g id="NAME">%s</xliff:g> në ekran të plotë për pamje më të mirë"</string>
<string name="done_label" msgid="7283767013231718521">"U krye"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Rrëshqitësi rrethor i orëve"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Rrëshqitësi rrethor i minutave"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2558577..1e98cffc 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -623,16 +623,17 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометријски хардвер није доступан"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Потврда идентитета је отказана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Није препознато"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Лице није препознато"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Потврда идентитета је отказана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Нисте подесили ни PIN, ни шаблон, ни лозинку"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при потврди идентитета"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Користите закључавање екрана"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Употребите закључавање екрана да бисте наставили"</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Јако притисните сензор"</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Чврсто притисните сензор"</string>
<string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Препознавање отиска прста није успело. Пробајте поново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Обришите сензор за отисак прста и пробајте поново"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Обришите сензор и пробајте поново"</string>
- <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Јако притисните сензор"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Чврсто притисните сензор"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Превише споро сте померили прст. Пробајте поново."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте са другим отиском прста"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Превише је светло"</string>
@@ -1853,7 +1854,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Да бисте изашли, превуците надоле одозго."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Важи"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Ротирајте ради бољег приказа"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Изађите из подељеног екрана ради бољег приказа"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Отворите апликацију <xliff:g id="NAME">%s</xliff:g> преко целог екрана да бисте боље видели"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кружни клизач за сате"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кружни клизач за минуте"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 413206e..f05d9a3 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvara är inte tillgänglig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ansiktet känns inte igen"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen avbröts"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, mönster eller lösenord har inte angetts"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ett fel uppstod vid autentiseringen"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Svep nedåt från skärmens överkant för att avsluta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Rotera för att få en bättre vy"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Stäng delad skärm för att få en bättre vy"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Öppna <xliff:g id="NAME">%s</xliff:g> i fullskärmsläget för att få en bättre vy"</string>
<string name="done_label" msgid="7283767013231718521">"Klart"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Cirkelreglage för timmar"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Cirkelreglage för minuter"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cf4273e..62a96c5 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maunzi ya bayometriki hayapatikani"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Imeghairi uthibitishaji"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Hayatambuliki"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Imeshindwa kutambua uso"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Imeghairi uthibitishaji"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Hujaweka pin, mchoro au nenosiri"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Hitilafu imetokea wakati wa uthibitishaji"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Ili kuondoka, telezesha kidole kutoka juu hadi chini."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Nimeelewa"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Zungusha ili upate mwonekano bora"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Funga skrini iliyogawanywa ili upate mwonekano bora"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Fungua <xliff:g id="NAME">%s</xliff:g> kwenye skrini nzima ili uone maudhui kwa urahisi"</string>
<string name="done_label" msgid="7283767013231718521">"Imekamilika"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kitelezi cha mviringo wa saa"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kitelezi cha mviringo wa dakika"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index ce18671..e69d1c8 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"அங்கீகரிப்பு ரத்தானது"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"அடையாளங்காணபடவில்லை"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"முகத்தைக் கண்டறிய முடியவில்லை"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"அங்கீகரிப்பு ரத்தானது"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"பின்னோ, பேட்டர்னோ, கடவுச்சொல்லோ அமைக்கப்படவில்லை"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"அங்கீகரிப்பதில் பிழை"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"புரிந்தது"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"சிறந்த காட்சிக்கு சுழற்றுங்கள்"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"சிறந்த காட்சிக்கு திரைப் பிரிப்புப் பயன்முறையில் இருந்து வெளியேறுங்கள்"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"சிறந்த காட்சிக்கு, <xliff:g id="NAME">%s</xliff:g> ஆப்ஸை முழுத்திரைப் பயன்முறையில் திறக்கவும்"</string>
<string name="done_label" msgid="7283767013231718521">"முடிந்தது"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"மணிநேர வட்ட வடிவ ஸ்லைடர்"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 81085e3..022740d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"బయోమెట్రిక్ హార్డ్వేర్ అందుబాటులో లేదు"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"గుర్తించలేదు"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ముఖం గుర్తించబడలేదు"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"పిన్, ఆకృతి లేదా పాస్వర్డ్ సెట్ చేయబడలేదు"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ప్రామాణీకరిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
@@ -1200,7 +1201,7 @@
<string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయి"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"దీన్ని ఉపయోగించి పంపండి"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$sని ఉపయోగించి పంపండి"</string>
- <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"పంపు"</string>
+ <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"పంపండి"</string>
<string name="whichHomeApplication" msgid="8276350727038396616">"హోమ్ యాప్ను ఎంచుకోండి"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"%1$sని హోమ్గా ఉపయోగించండి"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
@@ -1332,7 +1333,7 @@
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ఒక మెసేజ్ను <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>కి పంపాలనుకుంటోంది."</string>
<string name="sms_short_code_details" msgid="2723725738333388351">"దీని వలన మీ మొబైల్ ఖాతాకు "<b>"ఛార్జీలు విధించబడవచ్చు"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"దీని వలన మీ మొబైల్ ఖాతాకు ఛార్జీలు విధించబడవచ్చు."</b></string>
- <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"పంపు"</string>
+ <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"పంపండి"</string>
<string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"రద్దు చేయండి"</string>
<string name="sms_short_code_remember_choice" msgid="1374526438647744862">"నా ఎంపికను గుర్తుంచుకో"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"మీరు దీన్ని తర్వాత సెట్టింగ్లు > అనువర్తనాలులో మార్చవచ్చు"</string>
@@ -1472,7 +1473,7 @@
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"విడ్జెట్ను జోడించడం సాధ్యపడలేదు."</string>
<string name="ime_action_go" msgid="5536744546326495436">"వెళ్లు"</string>
<string name="ime_action_search" msgid="4501435960587287668">"సెర్చ్"</string>
- <string name="ime_action_send" msgid="8456843745664334138">"పంపు"</string>
+ <string name="ime_action_send" msgid="8456843745664334138">"పంపండి"</string>
<string name="ime_action_next" msgid="4169702997635728543">"తర్వాత"</string>
<string name="ime_action_done" msgid="6299921014822891569">"పూర్తయింది"</string>
<string name="ime_action_previous" msgid="6548799326860401611">"మునుపటి"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"నిష్క్రమించడానికి, పై నుండి క్రిందికి స్వైప్ చేయండి."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"అర్థమైంది"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"మెరుగైన వీక్షణ కోసం తిప్పండి"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"మెరుగైన వీక్షణ కోసం స్ప్లిట్ స్క్రీన్ నుండి నిష్క్రమించండి"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"మెరుగైన వీక్షణ కోసం <xliff:g id="NAME">%s</xliff:g>ను ఫుల్ స్క్రీన్లో తెరవండి"</string>
<string name="done_label" msgid="7283767013231718521">"పూర్తయింది"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"గంటల వృత్తాకార స్లయిడర్"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"నిమిషాల వృత్తాకార స్లయిడర్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 97ff393..83c92e9 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ไม่รู้จัก"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"ไม่รู้จักใบหน้า"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ไม่ได้ตั้ง PIN, รูปแบบ หรือรหัสผ่าน"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"การตรวจสอบข้อผิดพลาด"</string>
@@ -658,7 +659,7 @@
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
<string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"ใช้เซ็นเซอร์ลายนิ้วมือไม่ได้ โปรดติดต่อผู้ให้บริการซ่อม"</string>
<string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"กดปุ่มเปิด/ปิดแล้ว"</string>
- <string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้วมือ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ใช้ลายนิ้วมือ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอ"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"หากต้องการออก ให้เลื่อนลงจากด้านบน"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"รับทราบ"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"หมุนเพื่อรับมุมมองที่ดียิ่งขึ้น"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"ออกจากโหมดแยกหน้าจอเพื่อรับมุมมองที่ดียิ่งขึ้น"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"เปิด <xliff:g id="NAME">%s</xliff:g> ในโหมดเต็มหน้าจอเพื่อรับมุมมองที่ดียิ่งขึ้น"</string>
<string name="done_label" msgid="7283767013231718521">"เสร็จสิ้น"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ตัวเลื่อนหมุนระบุนาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e573679..fc443e9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Walang biometric hardware"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Nakansela ang pag-authenticate"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Hindi nakilala"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Hindi nakilala ang mukha"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Nakansela ang pag-authenticate"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Walang itinakdang pin, pattern, o password"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Nagkaroon ng error sa pag-authenticate"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Upang lumabas, mag-swipe mula sa itaas pababa."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Nakuha ko"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"I-rotate para sa mas magandang view"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Lumabas sa split screen para sa mas magandang view"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Buksan ang <xliff:g id="NAME">%s</xliff:g> sa full screen para sa mas magandang view"</string>
<string name="done_label" msgid="7283767013231718521">"Tapos na"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Pabilog na slider ng mga oras"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Pabilog na slider ng mga minuto"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 13c45ed..e83bbc3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biyometrik donanım kullanılamıyor"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Kimlik doğrulama iptal edildi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmadı"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Yüz tanınmadı"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Kimlik doğrulama iptal edildi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, desen veya şifre seti yok"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Kimlik doğrulama sırasında hata oluştu"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Anladım"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Daha iyi bir görünüm elde etmek için ekranı döndürün"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Daha iyi bir görünüm elde etmek için bölünmüş ekrandan çıkın"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Daha iyi görünüm için <xliff:g id="NAME">%s</xliff:g> uygulamasını açın"</string>
<string name="done_label" msgid="7283767013231718521">"Bitti"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Saat kaydırma çemberi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Dakika kaydırma çemberi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4694c37..11877ec 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -624,6 +624,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біометричне апаратне забезпечення недоступне"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Автентифікацію скасовано"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не розпізнано"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Обличчя не розпізнано"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Автентифікацію скасовано"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не вказано PIN-код, ключ або пароль"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Помилка автентифікації"</string>
@@ -1854,7 +1855,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Щоб вийти, проведіть пальцем зверху вниз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Оберніть для кращого огляду"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Для кращого огляду вийдіть із режиму розділення екрана"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Для кращого огляду відкрийте додаток <xliff:g id="NAME">%s</xliff:g> на весь екран"</string>
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Вибір годин на циферблаті"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Вибір хвилин на циферблаті"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3a243c6..4b508c7 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تصدیق کا عمل منسوخ ہو گیا"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"تسلیم شدہ نہیں ہے"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"چہرے کی شناخت نہیں ہو سکی"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"تصدیق کا عمل منسوخ ہو گیا"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"کوئی پن، پیٹرن، یا پاس ورڈ سیٹ نہیں ہے"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خرابی کی توثیق ہو رہی ہے"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"خارج ہونے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"سمجھ آ گئی"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"بہتر منظر کے لیے گھمائیں"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"بہتر منظر کے لیے اسپلٹ اسکرین سے باہر نکلیں"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"بہتر منظر کے لیے <xliff:g id="NAME">%s</xliff:g> کو فُل اسکرین میں کھولیں"</string>
<string name="done_label" msgid="7283767013231718521">"ہو گیا"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"گھنٹوں کا سرکلر سلائیڈر"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"منٹس سرکلر سلائیڈر"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 9fc0e5d..2c52936 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik sensor ishlamayapti"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikatsiya bekor qilindi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Aniqlanmadi"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Yuz aniqlanmadi"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikatsiya bekor qilindi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN kod, grafik kalit yoki parol sozlanmagan"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikatsiya amalga oshmadi"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Chiqish uchun tepadan pastga torting."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Yaxshiroq koʻrish uchun kamerani buring"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Yaxshiroq koʻrish uchun ajratilgan ekran rejimidan chiqing"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Yaxshiroq koʻrish uchun butun ekranda <xliff:g id="NAME">%s</xliff:g> ilovasini oching"</string>
<string name="done_label" msgid="7283767013231718521">"Tayyor"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Doiradan soatni tanlang"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Doiradan daqiqani tanlang"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7a72473..584e5bb 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Không nhận dạng được"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Không nhận dạng được khuôn mặt"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Đã hủy xác thực"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Chưa đặt mã PIN, hình mở khóa hoặc mật khẩu"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Lỗi khi xác thực"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Để thoát, hãy vuốt từ trên cùng xuống dưới."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Xoay để xem dễ hơn"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Thoát chế độ chia đôi màn hình để xem dễ hơn"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Mở <xliff:g id="NAME">%s</xliff:g> ở chế độ toàn màn hình để xem dễ hơn"</string>
<string name="done_label" msgid="7283767013231718521">"Xong"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Thanh trượt giờ hình tròn"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Thanh trượt phút hình tròn"</string>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index f34d9f9..12bc406 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -30,27 +30,27 @@
-->
<resources>
<style name="Animation.Material.Activity" parent="Animation.Activity">
- <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
+ <item name="activityOpenEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="activityOpenRemoteViewsEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="activityOpenExitAnimation">@null</item>
<item name="activityCloseEnterAnimation">@null</item>
- <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
+ <item name="activityCloseExitAnimation">@anim/rounded_window_exit</item>
+ <item name="taskOpenEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="taskOpenExitAnimation">@null</item>
<item name="taskCloseEnterAnimation">@null</item>
- <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskToFrontEnterAnimation">@null</item>
- <item name="taskToFrontExitAnimation">@anim/slide_out_micro</item>
+ <item name="taskCloseExitAnimation">@anim/rounded_window_exit</item>
+ <item name="taskToFrontEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="taskToFrontExitAnimation">@null</item>
<item name="taskToBackEnterAnimation">@null</item>
- <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
+ <item name="taskToBackExitAnimation">@anim/rounded_window_exit</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
- <item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
+ <item name="wallpaperOpenExitAnimation">@anim/rounded_window_exit</item>
+ <item name="wallpaperCloseEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="wallpaperCloseExitAnimation">@null</item>
<item name="wallpaperIntraOpenEnterAnimation">@null</item>
- <item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
- <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
+ <item name="wallpaperIntraOpenExitAnimation">@anim/rounded_window_exit</item>
+ <item name="wallpaperIntraCloseEnterAnimation">@anim/rounded_window_enter</item>
+ <item name="wallpaperIntraCloseExitAnimation">@null</item>
</style>
<style name="PreferenceFragment.Material" parent="BasePreferenceFragment">
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d183446..c8cc398 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生物识别硬件无法使用"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"身份验证已取消"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"无法识别"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"无法识别面孔"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"身份验证已取消"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未设置任何 PIN 码、图案和密码"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"进行身份验证时出错"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"要退出,请从顶部向下滑动。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"旋转可改善预览效果"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"退出分屏可改善预览效果"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"在全屏模式下打开“<xliff:g id="NAME">%s</xliff:g>”可改善预览效果"</string>
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小时转盘"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分钟转盘"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 5bc8a88..00f94b4 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物識別硬件"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"未能識別"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"無法辨識面孔"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN、圖案或密碼"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"由頂部向下滑動即可退出。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"旋轉以改善預覽效果"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"退出分割螢幕,以改善預覽效果"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"以全螢幕模式開啟「<xliff:g id="NAME">%s</xliff:g>」,以改善預覽效果"</string>
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小時環形滑桿"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分鐘環形滑桿"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b55d263..c04fe7a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物特徵辨識硬體"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"無法辨識"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"無法辨識臉孔"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN 碼、解鎖圖案或密碼"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"如要退出,請從畫面頂端向下滑動。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"旋轉螢幕以瀏覽完整的檢視畫面"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"結束分割畫面以全螢幕瀏覽"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"如要享有更優質的預覽體驗,可透過全螢幕模式開啟「<xliff:g id="NAME">%s</xliff:g>」"</string>
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小時數環狀滑桿"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分鐘數環狀滑桿"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2bb99b0..84a6802 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -622,6 +622,7 @@
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"I-Biometric hardware ayitholakali"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ukufakazela ubuqiniso kukhanseliwe"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Akwaziwa"</string>
+ <string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ubuso abaziwa"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ukufakazela ubuqiniso kukhanseliwe"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ayikho iphinikhodi, iphethini, noma iphasiwedi esethiwe"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Iphutha lokufakazela ubuqiniso"</string>
@@ -1852,7 +1853,7 @@
<string name="immersive_cling_description" msgid="7092737175345204832">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ngiyitholile"</string>
<string name="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"Zungezisa ukuze uthole ukubuka okungcono"</string>
- <string name="display_rotation_camera_compat_toast_in_split_screen" msgid="8393302456336805466">"Phuma ekuhlukaniseni isikrini ukuze ubuke kangcono"</string>
+ <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"Vula i-<xliff:g id="NAME">%s</xliff:g> kusikrini esigcwele ngokubuka okungcono"</string>
<string name="done_label" msgid="7283767013231718521">"Kwenziwe"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Amahora weslayidi esiyindingilizi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Amaminithi weslayidi esiyindingilizi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06ba4da..d05c10f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4803,8 +4803,6 @@
<!-- Size of icon shown beside a preference locked by admin -->
<dimen name="config_restrictedIconSize">@dimen/restricted_icon_size_material</dimen>
- <string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
-
<!-- Component name that should be granted Notification Assistant access -->
<string name="config_defaultAssistantAccessComponent" translatable="false">android.ext.services/android.ext.services.notification.Assistant</string>
@@ -4834,12 +4832,6 @@
<!-- Default value set for battery percentage in status bar false = disabled, true = enabled -->
<bool name="config_defaultBatteryPercentageSetting">false</bool>
- <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
- <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
-
- <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. -->
- <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer>
-
<!-- Model of potentially misprovisioned devices. If none is specified in an overlay, an
empty string is passed in. -->
<string name="config_misprovisionedDeviceModel" translatable="false"></string>
@@ -5726,6 +5718,9 @@
TODO(b/255532890) Enable when ignoreOrientationRequest is set -->
<bool name="config_letterboxIsEnabledForTranslucentActivities">false</bool>
+ <!-- Whether per-app user aspect ratio override settings is enabled -->
+ <bool name="config_appCompatUserAppAspectRatioSettingsIsEnabled">false</bool>
+
<!-- Whether sending compat fake focus for split screen resumed activities is enabled.
Needed because some game engines wait to get focus before drawing the content of
the app which isn't guaranteed by default in multi-window modes. -->
diff --git a/core/res/res/values/config_battery_saver.xml b/core/res/res/values/config_battery_saver.xml
new file mode 100644
index 0000000..eb396df
--- /dev/null
+++ b/core/res/res/values/config_battery_saver.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (C) 2023 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. Do not translate.
+
+ NOTE: The naming convention is "config_camelCaseValue". Some legacy
+ entries do not follow the convention, but all new entries should. -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
+
+ <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
+ <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
+
+ <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. -->
+ <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.adjustBrightnessFactor -->
+ <item name="config_batterySaver_full_adjustBrightnessFactor" format="float" type="dimen">
+ .5
+ </item>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.deferFullBackup -->
+ <bool name="config_batterySaver_full_deferFullBackup">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.deferKeyValueBackup -->
+ <bool name="config_batterySaver_full_deferKeyValueBackup">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.disableAnimation -->
+ <bool name="config_batterySaver_full_disableAnimation">false</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.disableAod -->
+ <bool name="config_batterySaver_full_disableAod">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.disableLaunchBoost -->
+ <bool name="config_batterySaver_full_disableLaunchBoost">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.disableOptionalSensors -->
+ <bool name="config_batterySaver_full_disableOptionalSensors">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.disableVibration -->
+ <bool name="config_batterySaver_full_disableVibration">false</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.enableAdjustBrightness -->
+ <bool name="config_batterySaver_full_enableAdjustBrightness">false</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.enableDataSaver -->
+ <bool name="config_batterySaver_full_enableDataSaver">false</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.enableFirewall -->
+ <bool name="config_batterySaver_full_enableFirewall">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.enableNightMode -->
+ <bool name="config_batterySaver_full_enableNightMode">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.enableQuickDoze -->
+ <bool name="config_batterySaver_full_enableQuickDoze">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.forceAllAppsStandby -->
+ <bool name="config_batterySaver_full_forceAllAppsStandby">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.forceBackgroundCheck -->
+ <bool name="config_batterySaver_full_forceBackgroundCheck">true</bool>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.locationMode
+ (LOCATION_MODE_FOREGROUND_ONLY) -->
+ <integer name="config_batterySaver_full_locationMode">3</integer>
+
+ <!-- Default for BatterySaverPolicy.DEFAULT_FULL_POLICY.soundTriggerMode
+ (SOUND_TRIGGER_MODE_CRITICAL_ONLY) -->
+ <integer name="config_batterySaver_full_soundTriggerMode">1</integer>
+</resources>
+
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 4ae54a0..08c40ba 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -67,6 +67,15 @@
<bool name="auto_data_switch_ping_test_before_switch">true</bool>
<java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" />
+ <!-- Define the tolerated gap of score for auto data switch decision, larger than which the
+ device will switch to the SIM with higher score. The score is used in conjunction with the
+ score table defined in
+ CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.
+ If 0, the device always switch to the higher score SIM.
+ If < 0, the network type and signal strength based auto switch is disabled. -->
+ <integer name="auto_data_switch_score_tolerance">3000</integer>
+ <java-symbol type="integer" name="auto_data_switch_score_tolerance" />
+
<!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
tunnels across service restart. If iwlan tunnels are not persisted across restart,
Framework will clean up dangling data connections when service restarts -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2c72f45..7f66a83 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5379,7 +5379,7 @@
<!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
<string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
<!-- Title of the dialog shown when the permissioncontroller is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
- <string name="app_streaming_blocked_title_for_permission_dialog">Permission needed</string>
+ <string name="app_streaming_blocked_title_for_permission_dialog">Permission request suppressed</string>
<!-- Title of the dialog shown when the camera permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
<string name="app_streaming_blocked_title_for_camera_dialog">Camera unavailable</string>
<!-- Title of the dialog shown when the fingerprint permission is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
@@ -5400,6 +5400,12 @@
<string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
<!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
<string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
+ <!-- Message shown when a runtime permission request is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv">This app is requesting additional permissions, but permissions can’t be granted in a streaming session. Grant the permission on your Android TV device first.</string>
+ <!-- Message shown when a runtime permission request is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet">This app is requesting additional permissions, but permissions can’t be granted in a streaming session. Grant the permission on your tablet first.</string>
+ <!-- Message shown when a runtime permission request is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
+ <string name="app_streaming_blocked_message_for_permission_request" product="default">This app is requesting additional permissions, but permissions can’t be granted in a streaming session. Grant the permission on your phone first.</string>
<!-- Message shown when an app being streamed to another device requests authentication such as via the biometrics API, and the user needs to complete the on their device. [CHAR LIMIT=NONE] -->
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv">This app is requesting additional security. Try on your Android TV device instead.</string>
<!-- Message shown when an app being streamed to another device requests authentication such as via the biometrics API, and the user needs to complete the on their device. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 070004f..bb4b16c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3349,6 +3349,7 @@
<java-symbol type="string" name="app_streaming_blocked_title_for_playstore_dialog" />
<java-symbol type="string" name="app_streaming_blocked_title_for_settings_dialog" />
<java-symbol type="string" name="app_streaming_blocked_message" />
+ <java-symbol type="string" name="app_streaming_blocked_message_for_permission_request" />
<java-symbol type="string" name="app_streaming_blocked_message_for_fingerprint_dialog" />
<java-symbol type="string" name="app_streaming_blocked_message_for_settings_dialog" />
@@ -3936,7 +3937,6 @@
<!-- From media projection -->
<java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
- <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
<!-- Compile SDK check -->
<java-symbol type="layout" name="unsupported_compile_sdk_dialog_content" />
@@ -4000,11 +4000,30 @@
<java-symbol type="string" name="notification_app_name_system" />
<java-symbol type="string" name="notification_app_name_settings" />
+ <!-- Battery saver config -->
<java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" />
+ <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
<java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
<java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" />
<java-symbol type="string" name="config_batterySaverScheduleProvider" />
<java-symbol type="string" name="config_powerSaveModeChangedListenerPackage" />
+ <java-symbol type="dimen" name="config_batterySaver_full_adjustBrightnessFactor" />
+ <java-symbol type="bool" name="config_batterySaver_full_deferFullBackup" />
+ <java-symbol type="bool" name="config_batterySaver_full_deferKeyValueBackup" />
+ <java-symbol type="bool" name="config_batterySaver_full_disableAnimation" />
+ <java-symbol type="bool" name="config_batterySaver_full_disableAod" />
+ <java-symbol type="bool" name="config_batterySaver_full_disableLaunchBoost" />
+ <java-symbol type="bool" name="config_batterySaver_full_disableOptionalSensors" />
+ <java-symbol type="bool" name="config_batterySaver_full_disableVibration" />
+ <java-symbol type="bool" name="config_batterySaver_full_enableAdjustBrightness" />
+ <java-symbol type="bool" name="config_batterySaver_full_enableDataSaver" />
+ <java-symbol type="bool" name="config_batterySaver_full_enableFirewall" />
+ <java-symbol type="bool" name="config_batterySaver_full_enableNightMode" />
+ <java-symbol type="bool" name="config_batterySaver_full_enableQuickDoze" />
+ <java-symbol type="bool" name="config_batterySaver_full_forceAllAppsStandby" />
+ <java-symbol type="bool" name="config_batterySaver_full_forceBackgroundCheck" />
+ <java-symbol type="integer" name="config_batterySaver_full_locationMode" />
+ <java-symbol type="integer" name="config_batterySaver_full_soundTriggerMode" />
<!-- For car devices -->
<java-symbol type="string" name="car_loading_profile" />
@@ -4439,9 +4458,6 @@
<!-- Set to true to make assistant show in front of the dream/screensaver. -->
<java-symbol type="bool" name="config_assistantOnTopOfDream"/>
- <!-- Set to true to enable letterboxing on translucent activities. -->
- <java-symbol type="bool" name="config_letterboxIsEnabledForTranslucentActivities" />
-
<java-symbol type="string" name="config_overrideComponentUiPackage" />
<java-symbol type="string" name="notification_channel_network_status" />
@@ -4536,6 +4552,12 @@
<java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
<java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
<java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" />
+ <!-- Set to true to enable letterboxing on translucent activities. -->
+ <java-symbol type="bool" name="config_letterboxIsEnabledForTranslucentActivities" />
+
+ <!-- Whether per-app user aspect ratio override settings is enabled -->
+ <java-symbol type="bool" name="config_appCompatUserAppAspectRatioSettingsIsEnabled" />
+
<java-symbol type="bool" name="config_isCompatFakeFocusEnabled" />
<java-symbol type="bool" name="config_isWindowManagerCameraCompatTreatmentEnabled" />
<java-symbol type="bool" name="config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index df3ae0e..f28da1f 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -162,7 +162,7 @@
<shortcode country="jp" pattern="\\d{1,5}" free="8083" />
<!-- Kenya: 5 digits, known premium codes listed -->
- <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520" />
+ <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520|23342" />
<!-- Kyrgyzstan: 4 digits, known premium codes listed -->
<shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
@@ -235,6 +235,9 @@
<!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ -->
<shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>
+ <!-- Rwanda: 4 digits -->
+ <shortcode country="rw" pattern="\\d{4}" free="5060" />
+
<!-- Saudi Arabia -->
<shortcode country="sa" pattern="\\d{1,5}" free="8145" />
diff --git a/core/tests/coretests/res/values/overlayable_icons_test.xml b/core/tests/coretests/res/values/overlayable_icons_test.xml
index 7ea1848..6a50e9a 100644
--- a/core/tests/coretests/res/values/overlayable_icons_test.xml
+++ b/core/tests/coretests/res/values/overlayable_icons_test.xml
@@ -21,7 +21,6 @@
<item>@*android:drawable/ic_audio_alarm</item>
<item>@*android:drawable/ic_audio_alarm_mute</item>
<item>@*android:drawable/ic_battery_80_24dp</item>
- <item>@*android:drawable/ic_bluetooth_share_icon</item>
<item>@*android:drawable/ic_bt_headphones_a2dp</item>
<item>@*android:drawable/ic_bt_headset_hfp</item>
<item>@*android:drawable/ic_bt_hearing_aid</item>
diff --git a/core/tests/coretests/src/android/app/KeyguardManagerTest.java b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
index 7231fbd..958906c 100644
--- a/core/tests/coretests/src/android/app/KeyguardManagerTest.java
+++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
@@ -26,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -209,6 +211,42 @@
verifyDeviceLockedAndRemoveLock();
}
+ @Test
+ public void createConfirmDeviceCredentialForRemoteValidationIntent() {
+ RemoteLockscreenValidationSession remoteLockscreenValidationSession =
+ new RemoteLockscreenValidationSession.Builder()
+ .setSourcePublicKey("sourcePublicKey".getBytes())
+ .build();
+ ComponentName componentName = new ComponentName("pkg", "cls");
+ String title = "title";
+ String description = "description";
+ String checkboxLabel = "checkboxLabel";
+ String alternateButtonLabel = "alternateButtonLabel";
+
+ Intent intent = mKeyguardManager.createConfirmDeviceCredentialForRemoteValidationIntent(
+ remoteLockscreenValidationSession,
+ componentName,
+ title,
+ description,
+ checkboxLabel,
+ alternateButtonLabel
+ );
+
+ assertNotNull(intent);
+ assertEquals(KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL, intent.getAction());
+ assertEquals(remoteLockscreenValidationSession,
+ intent.getParcelableExtra(
+ KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+ RemoteLockscreenValidationSession.class));
+ assertEquals(componentName,
+ intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class));
+ assertEquals(title, intent.getStringExtra(KeyguardManager.EXTRA_TITLE));
+ assertEquals(description, intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION));
+ assertEquals(checkboxLabel, intent.getStringExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL));
+ assertEquals(alternateButtonLabel,
+ intent.getStringExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL));
+ }
+
private void verifyDeviceLockedAndRemoveLock() {
assertTrue(mKeyguardManager.isDeviceSecure());
assertTrue("Failed to remove new password that was set in the test case.",
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
index 7fe38a5..0941a2b 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
@@ -25,7 +25,6 @@
import android.app.Activity;
import android.compat.testing.PlatformCompatChangeRule;
import android.os.Bundle;
-import android.platform.test.annotations.IwTest;
import android.platform.test.annotations.PlatinumTest;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
@@ -74,7 +73,6 @@
}
@PlatinumTest(focusArea = "accessibility")
- @IwTest(focusArea = "accessibility")
@Test
public void testFontsScaleNonLinearly() {
final ActivityScenario<TestActivity> scenario = rule.getScenario();
@@ -106,7 +104,6 @@
}
@PlatinumTest(focusArea = "accessibility")
- @IwTest(focusArea = "accessibility")
@Test
public void testOnConfigurationChanged_doesNotCrash() {
final ActivityScenario<TestActivity> scenario = rule.getScenario();
@@ -121,7 +118,6 @@
}
@PlatinumTest(focusArea = "accessibility")
- @IwTest(focusArea = "accessibility")
@Test
public void testUpdateConfiguration_doesNotCrash() {
final ActivityScenario<TestActivity> scenario = rule.getScenario();
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
index 8abcf17..944e2b0 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
@@ -118,6 +118,41 @@
return "INSERT INTO t1 (i, d, t) VALUES (?1, ?2, ?3)";
}
+ /**
+ * Create a database with one table with 12 columns.
+ */
+ private void createWideDatabase() {
+ StringBuilder sp = new StringBuilder();
+ sp.append(String.format("i%d int", 0));
+ for (int i = 1; i < 12; i++) {
+ sp.append(String.format(", i%d int", i));
+ }
+ mDatabase.beginTransaction();
+ try {
+ mDatabase.execSQL("CREATE TABLE t1 (" + sp.toString() + ")");
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ /**
+ * A 12-value insert for the wide database.
+ */
+ private String createWideInsert() {
+ StringBuilder sp = new StringBuilder();
+ sp.append("INSERT INTO t1 (i0");
+ for (int i = 1; i < 12; i++) {
+ sp.append(String.format(", i%d", i));
+ }
+ sp.append(") VALUES (?");
+ for (int i = 1; i < 12; i++) {
+ sp.append(", ?");
+ }
+ sp.append(")");
+ return sp.toString();
+ }
+
@Test
public void testSingleTransaction() {
createSimpleDatabase();
@@ -701,6 +736,76 @@
}
}
+ private int wideVal(int i, int j) {
+ return i + j;
+ }
+
+ @Test
+ public void testSpeedWideQuery() {
+ final int size = 100000;
+
+ createWideDatabase();
+
+ // Populate the database.
+ mDatabase.beginTransaction();
+ try {
+ try (var s = mDatabase.createRawStatement(createWideInsert())) {
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < 12; j++) {
+ s.bindInt(j+1, wideVal(i, j));
+ }
+ boolean r = s.step();
+ // No row is returned by this query.
+ assertFalse(r);
+ s.reset();
+ }
+ }
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+
+ final String query = "SELECT * FROM t1";
+
+ // Iterate over the database.
+ mDatabase.beginTransactionReadOnly();
+ try {
+ long start = SystemClock.uptimeMillis();
+ try (var s = mDatabase.createRawStatement(query)) {
+ for (int i = 0; i < size; i++) {
+ assertTrue(s.step());
+ for (int j = 0; j < 12; j++) {
+ assertEquals(s.getInt(j), wideVal(i, j));
+ }
+ }
+ }
+ long elapsed = SystemClock.uptimeMillis() - start;
+ Log.i(TAG, "timing statement wide: " + elapsed + "ms");
+ } finally {
+ mDatabase.endTransaction();
+ }
+
+ // Iterate over the database using cursors.
+ mDatabase.beginTransactionReadOnly();
+ try {
+ long start = SystemClock.uptimeMillis();
+ try (Cursor c = mDatabase.rawQuery(query, null)) {
+ c.moveToFirst();
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < 12; j++) {
+ assertEquals(c.getInt(j), wideVal(i, j));
+ }
+ c.moveToNext();
+ }
+ }
+ long elapsed = SystemClock.uptimeMillis() - start;
+ mDatabase.setTransactionSuccessful();
+ Log.i(TAG, "timing cursor wide: " + elapsed + "ms");
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
@Test
public void testSpeedRecursive() {
@@ -719,7 +824,7 @@
}
}
long elapsed = SystemClock.uptimeMillis() - start;
- Log.i(TAG, "timing statement recursive = " + elapsed + "ms");
+ Log.i(TAG, "timing statement recursive: " + elapsed + "ms");
} finally {
mDatabase.endTransaction();
}
@@ -734,7 +839,7 @@
}
}
long elapsed = SystemClock.uptimeMillis() - start;
- Log.i(TAG, "timing cursor recursive = " + elapsed + "ms");
+ Log.i(TAG, "timing cursor recursive: " + elapsed + "ms");
} finally {
mDatabase.endTransaction();
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index 7cbf3ffa..84252f9 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -32,6 +32,7 @@
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Intent;
+import android.content.pm.ParceledListSlice;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
@@ -135,7 +136,7 @@
// configure the mock service behavior
when(mMockService.getInstalledAccessibilityServiceList(anyInt()))
- .thenReturn(expectedServices);
+ .thenReturn(new ParceledListSlice<>(expectedServices));
// invoke the method under test
AccessibilityManager manager = createManager(true);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 57a1376..681ba9c 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -43,6 +43,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
@@ -111,7 +112,8 @@
when(mResolveInfo.loadLabel(any(PackageManager.class))).thenReturn(TEST_LABEL);
when(mAccessibilityServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(
- anyInt())).thenReturn(Collections.singletonList(mAccessibilityServiceInfo));
+ anyInt())).thenReturn(new ParceledListSlice<>(
+ Collections.singletonList(mAccessibilityServiceInfo)));
when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
anyString(), anyInt(), anyInt())).thenReturn(true);
TestAccessibilityShortcutChooserActivity.setupForTesting(mAccessibilityManagerService);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 9763679..2de1230 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -55,6 +55,7 @@
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
@@ -150,7 +151,7 @@
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
- .thenReturn(Collections.singletonList(mServiceInfo));
+ .thenReturn(new ParceledListSlice<>(Collections.singletonList(mServiceInfo)));
// Use the extra level of indirection in the object to mock framework objects
AccessibilityManager accessibilityManager =
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index 516dee7..faccf1a 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertThrows;
+import android.os.BadParcelableException;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -163,6 +164,45 @@
}
@Test
+ public void createFromBadBundle() {
+ Parcel data = Parcel.obtain();
+ int bundleLenPos = data.dataPosition();
+ data.writeInt(0);
+ data.writeInt(0x4C444E42); // BaseBundle.BUNDLE_MAGIC
+
+ int bundleStart = data.dataPosition();
+
+ data.writeInt(1);
+ data.writeString("key");
+ data.writeInt(4);
+ int lazyValueLenPos = data.dataPosition();
+ data.writeInt(0);
+ int lazyValueStart = data.dataPosition();
+ data.writeString("com.android.internal.os.LongArrayMultiStateCounter");
+
+ // Invalid int16 value
+ data.writeInt(0x10000); // stateCount
+ data.writeInt(10); // arrayLength
+ for (int i = 0; i < 0x10000; ++i) {
+ data.writeLong(0);
+ }
+
+ backPatchLength(data, lazyValueLenPos, lazyValueStart);
+ backPatchLength(data, bundleLenPos, bundleStart);
+ data.setDataPosition(0);
+
+ assertThrows(BadParcelableException.class,
+ () -> data.readBundle().getParcelable("key", LongArrayMultiStateCounter.class));
+ }
+
+ private static void backPatchLength(Parcel parcel, int lengthPos, int startPos) {
+ int endPos = parcel.dataPosition();
+ parcel.setDataPosition(lengthPos);
+ parcel.writeInt(endPos - startPos);
+ parcel.setDataPosition(endPos);
+ }
+
+ @Test
public void combineValues() {
long[] values = new long[] {0, 1, 2, 3, 42};
LongArrayMultiStateCounter.LongArrayContainer container =
diff --git a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
index fc86ebe..3413753 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertThrows;
+import android.os.BadParcelableException;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -210,4 +211,42 @@
assertThrows(RuntimeException.class,
() -> LongMultiStateCounter.CREATOR.createFromParcel(parcel));
}
+
+ @Test
+ public void createFromBadBundle() {
+ Parcel data = Parcel.obtain();
+ int bundleLenPos = data.dataPosition();
+ data.writeInt(0);
+ data.writeInt(0x4C444E42); // BaseBundle.BUNDLE_MAGIC
+
+ int bundleStart = data.dataPosition();
+
+ data.writeInt(1);
+ data.writeString("key");
+ data.writeInt(4);
+ int lazyValueLenPos = data.dataPosition();
+ data.writeInt(0);
+ int lazyValueStart = data.dataPosition();
+ data.writeString("com.android.internal.os.LongMultiStateCounter");
+
+ // Invalid int16 value
+ data.writeInt(0x10000); // stateCount
+ for (int i = 0; i < 0x10000; ++i) {
+ data.writeLong(0);
+ }
+
+ backPatchLength(data, lazyValueLenPos, lazyValueStart);
+ backPatchLength(data, bundleLenPos, bundleStart);
+ data.setDataPosition(0);
+
+ assertThrows(BadParcelableException.class,
+ () -> data.readBundle().getParcelable("key", LongMultiStateCounter.class));
+ }
+
+ private static void backPatchLength(Parcel parcel, int lengthPos, int startPos) {
+ int endPos = parcel.dataPosition();
+ parcel.setDataPosition(lengthPos);
+ parcel.writeInt(endPos - startPos);
+ parcel.setDataPosition(endPos);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
index e6f10ad..3946cdf 100644
--- a/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
@@ -16,14 +16,19 @@
package com.android.internal.util;
+import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER;
+
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
import static com.android.internal.util.FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED;
import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
import static com.google.common.truth.Truth.assertThat;
+import android.provider.DeviceConfig;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,12 +45,22 @@
public class FakeLatencyTrackerTest {
private FakeLatencyTracker mFakeLatencyTracker;
+ private int mInitialSyncDisabledMode;
@Before
public void setUp() throws Exception {
+ mInitialSyncDisabledMode = DeviceConfig.getSyncDisabledMode();
+ DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE);
mFakeLatencyTracker = FakeLatencyTracker.create();
}
+ @After
+ public void tearDown() throws Exception {
+ DeviceConfig.setProperties(
+ new DeviceConfig.Properties.Builder(NAMESPACE_LATENCY_TRACKER).build());
+ DeviceConfig.setSyncDisabledMode(mInitialSyncDisabledMode);
+ }
+
@Test
public void testForceEnabled() throws Exception {
mFakeLatencyTracker.logAction(ACTION_SHOW_VOICE_INTERACTION, 1234);
diff --git a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
index 584ad20..f24894e 100644
--- a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
@@ -58,15 +58,21 @@
// Fake is used because it tests the real logic of LatencyTracker, and it only fakes the
// outcomes (PerfettoTrigger and FrameworkStatsLog).
private FakeLatencyTracker mLatencyTracker;
+ private int mInitialSyncDisabledMode;
@Before
public void setUp() throws Exception {
+ mInitialSyncDisabledMode = DeviceConfig.getSyncDisabledMode();
+ DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE);
mLatencyTracker = FakeLatencyTracker.create();
}
@After
- public void tearDown() {
+ public void tearDown() throws Exception {
mLatencyTracker.stopListeningForLatencyTrackerConfigChanges();
+ DeviceConfig.setProperties(
+ new DeviceConfig.Properties.Builder(NAMESPACE_LATENCY_TRACKER).build());
+ DeviceConfig.setSyncDisabledMode(mInitialSyncDisabledMode);
}
@Test
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 2e91c24..15d26eb 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -971,6 +971,23 @@
}
/**
+ * Configure the {@link android.graphics.RenderEffect} to apply to the backdrop contents of
+ * this RenderNode. This will apply a visual effect to the result of the backdrop contents
+ * of this RenderNode before the RenderNode is drawn into the destination. For example if
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)}
+ * is provided, the previous content behind this RenderNode will be blurred before the
+ * RenderNode is drawn in to the destination.
+ * @param renderEffect to be applied to the backdrop contents of this RenderNode. Passing
+ * null clears all previously configured RenderEffects
+ * @return True if the value changed, false if the new value was the same as the previous value.
+ * @hide
+ */
+ public boolean setBackdropRenderEffect(@Nullable RenderEffect renderEffect) {
+ return nSetBackdropRenderEffect(mNativeRenderNode,
+ renderEffect != null ? renderEffect.getNativeInstance() : 0);
+ }
+
+ /**
* Returns the translucency level of this display list.
*
* @return A value between 0.0f and 1.0f
@@ -1797,6 +1814,9 @@
private static native boolean nSetRenderEffect(long renderNode, long renderEffect);
@CriticalNative
+ private static native boolean nSetBackdropRenderEffect(long renderNode, long renderEffect);
+
+ @CriticalNative
private static native boolean nSetHasOverlappingRendering(long renderNode,
boolean hasOverlappingRendering);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 96190c4b..1e6e503 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -28,6 +28,7 @@
import android.util.Pair;
import android.view.Display;
import android.view.DisplayAddress;
+import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -36,6 +37,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.util.Objects;
@@ -229,27 +231,43 @@
* @since {@link WindowExtensions#VENDOR_API_LEVEL_3}
*/
@Override
+ @NonNull
public DisplayMetrics getRearDisplayMetrics() {
- DisplayMetrics metrics = null;
+ DisplayMetrics rearDisplayMetrics = null;
// DISPLAY_CATEGORY_REAR displays are only available when you are in the concurrent
// display state, so we have to look through all displays to match the address
- Display[] displays = mDisplayManager.getDisplays(
+ final Display[] displays = mDisplayManager.getDisplays(
DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+
+
for (int i = 0; i < displays.length; i++) {
DisplayAddress.Physical address =
(DisplayAddress.Physical) displays[i].getAddress();
if (mRearDisplayAddress == address.getPhysicalDisplayId()) {
- metrics = new DisplayMetrics();
- displays[i].getRealMetrics(metrics);
+ rearDisplayMetrics = new DisplayMetrics();
+ final Display rearDisplay = displays[i];
+
+ // We must always retrieve the metrics for the rear display regardless of if it is
+ // the default display or not.
+ rearDisplay.getRealMetrics(rearDisplayMetrics);
+
+ // TODO(b/287170025): This should be something like if (!rearDisplay.isEnabled)
+ // instead. Currently when the rear display is disabled, its state is STATE_OFF.
+ if (rearDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) {
+ final Display defaultDisplay = mDisplayManager
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ rotateRearDisplayMetricsIfNeeded(defaultDisplay.getRotation(),
+ rearDisplay.getRotation(), rearDisplayMetrics);
+ }
break;
}
}
synchronized (mLock) {
// Update the rear display metrics with our latest value if one was received
- if (metrics != null) {
- mRearDisplayMetrics = metrics;
+ if (rearDisplayMetrics != null) {
+ mRearDisplayMetrics = rearDisplayMetrics;
}
return Objects.requireNonNullElseGet(mRearDisplayMetrics, DisplayMetrics::new);
@@ -540,6 +558,34 @@
return mLastReportedRearDisplayPresentationStatus;
}
+ @VisibleForTesting
+ static void rotateRearDisplayMetricsIfNeeded(
+ @Surface.Rotation int defaultDisplayRotation,
+ @Surface.Rotation int rearDisplayRotation,
+ @NonNull DisplayMetrics inOutMetrics) {
+ // If the rear display has a non-zero rotation, it means the backing DisplayContent /
+ // DisplayRotation is fresh.
+ if (rearDisplayRotation != Surface.ROTATION_0) {
+ return;
+ }
+
+ // If the default display is 0 or 180, the rear display must also be 0 or 180.
+ if (defaultDisplayRotation == Surface.ROTATION_0
+ || defaultDisplayRotation == Surface.ROTATION_180) {
+ return;
+ }
+
+ final int heightPixels = inOutMetrics.heightPixels;
+ final int widthPixels = inOutMetrics.widthPixels;
+ inOutMetrics.widthPixels = heightPixels;
+ inOutMetrics.heightPixels = widthPixels;
+
+ final int noncompatHeightPixels = inOutMetrics.noncompatHeightPixels;
+ final int noncompatWidthPixels = inOutMetrics.noncompatWidthPixels;
+ inOutMetrics.noncompatWidthPixels = noncompatHeightPixels;
+ inOutMetrics.noncompatHeightPixels = noncompatWidthPixels;
+ }
+
/**
* Callback for the {@link DeviceStateRequest} to be notified of when the request has been
* activated or cancelled. This callback provides information to the client library
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
new file mode 100644
index 0000000..ccb4ebe
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
+import android.view.Surface;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowAreaComponentImplTests {
+
+ private final DisplayMetrics mTestDisplayMetrics = new DisplayMetrics();
+
+ @Before
+ public void setup() {
+ mTestDisplayMetrics.widthPixels = 1;
+ mTestDisplayMetrics.heightPixels = 2;
+ mTestDisplayMetrics.noncompatWidthPixels = 3;
+ mTestDisplayMetrics.noncompatHeightPixels = 4;
+ }
+
+ /**
+ * Cases where the rear display metrics does not need to be transformed.
+ */
+ @Test
+ public void testRotateRearDisplayMetrics_noTransformNeeded() {
+ final DisplayMetrics originalMetrics = new DisplayMetrics();
+ originalMetrics.setTo(mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_0, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_180, Surface.ROTATION_180, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_0, Surface.ROTATION_180, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_180, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+ }
+
+ /**
+ * Cases where the rear display metrics need to be transformed.
+ */
+ @Test
+ public void testRotateRearDisplayMetrics_transformNeeded() {
+ DisplayMetrics originalMetrics = new DisplayMetrics();
+ originalMetrics.setTo(mTestDisplayMetrics);
+
+ DisplayMetrics expectedMetrics = new DisplayMetrics();
+ expectedMetrics.setTo(mTestDisplayMetrics);
+ expectedMetrics.widthPixels = mTestDisplayMetrics.heightPixels;
+ expectedMetrics.heightPixels = mTestDisplayMetrics.widthPixels;
+ expectedMetrics.noncompatWidthPixels = mTestDisplayMetrics.noncompatHeightPixels;
+ expectedMetrics.noncompatHeightPixels = mTestDisplayMetrics.noncompatWidthPixels;
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_90, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(expectedMetrics, mTestDisplayMetrics);
+
+ mTestDisplayMetrics.setTo(originalMetrics);
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_270, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(expectedMetrics, mTestDisplayMetrics);
+ }
+}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 54978bd..7159893 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -42,16 +42,19 @@
filegroup {
name: "wm_shell_util-sources",
srcs: [
- "src/com/android/wm/shell/util/**/*.java",
- "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
- "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
- "src/com/android/wm/shell/common/TransactionPool.java",
- "src/com/android/wm/shell/common/bubbles/*.java",
- "src/com/android/wm/shell/common/TriangleShape.java",
"src/com/android/wm/shell/animation/Interpolators.java",
+ "src/com/android/wm/shell/animation/PhysicsAnimator.kt",
+ "src/com/android/wm/shell/common/bubbles/*.kt",
+ "src/com/android/wm/shell/common/bubbles/*.java",
+ "src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt",
+ "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
+ "src/com/android/wm/shell/common/TransactionPool.java",
+ "src/com/android/wm/shell/common/TriangleShape.java",
+ "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java",
"src/com/android/wm/shell/pip/PipContentOverlay.java",
"src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",
- "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java",
+ "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
+ "src/com/android/wm/shell/util/**/*.java",
],
path: "src",
}
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
index 01df006..f75d842 100644
--- a/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
@@ -16,5 +16,5 @@
-->
<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="20" />
+ <item android:color="@android:color/system_neutral1_500" android:lStar="6" />
</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 504839f..7e09c98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -422,6 +422,7 @@
}
if (mBubbleBarExpandedView != null) {
mBubbleBarExpandedView.cleanUpExpandedState();
+ mBubbleBarExpandedView = null;
}
if (mIntent != null) {
mIntent.unregisterCancelListener(mIntentCancelListener);
@@ -549,10 +550,10 @@
/**
* Set visibility of bubble in the expanded state.
*
- * @param visibility {@code true} if the expanded bubble should be visible on the screen.
- *
- * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
+ * <p>Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the expanded view in transparent.
+ *
+ * @param visibility {@code true} if the expanded bubble should be visible on the screen.
*/
@Override
public void setTaskViewVisibility(boolean visibility) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 1467741..cb03c09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -64,7 +64,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationListenerService;
@@ -80,8 +79,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.window.ScreenCapture;
-import android.window.ScreenCapture.ScreenCaptureListener;
-import android.window.ScreenCapture.ScreenshotSync;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -93,6 +91,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
+import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -144,16 +143,6 @@
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
- // TODO(b/256873975) Should use proper flag when available to shell/launcher
- /**
- * Whether bubbles are showing in the bubble bar from launcher. This is only available
- * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
- * to check all conditions that indicate if the bubble bar is in use.
- */
- private static final boolean BUBBLE_BAR_ENABLED =
- SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
-
-
/**
* Common interface to send updates to bubble views.
*/
@@ -196,6 +185,7 @@
private final ShellController mShellController;
private final ShellCommandHandler mShellCommandHandler;
private final IWindowManager mWmService;
+ private final BubbleProperties mBubbleProperties;
// Used to post to main UI thread
private final ShellExecutor mMainExecutor;
@@ -292,7 +282,8 @@
@ShellBackgroundThread ShellExecutor bgExecutor,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue,
- IWindowManager wmService) {
+ IWindowManager wmService,
+ BubbleProperties bubbleProperties) {
mContext = context;
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
@@ -329,6 +320,7 @@
mDragAndDropController = dragAndDropController;
mSyncQueue = syncQueue;
mWmService = wmService;
+ mBubbleProperties = bubbleProperties;
shellInit.addInitCallback(this::onInit, this);
}
@@ -519,11 +511,14 @@
/**
* Sets a listener to be notified of bubble updates. This is used by launcher so that
* it may render bubbles in itself. Only one listener is supported.
+ *
+ * <p>If bubble bar is supported, bubble views will be updated to switch to bar mode.
*/
public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) {
- if (isShowingAsBubbleBar()) {
- // Only set the listener if bubble bar is showing.
+ if (canShowAsBubbleBar() && listener != null) {
+ // Only set the listener if we can show the bubble bar.
mBubbleStateListener = listener;
+ setUpBubbleViewsForMode();
sendInitialListenerUpdate();
} else {
mBubbleStateListener = null;
@@ -532,9 +527,15 @@
/**
* Unregisters the {@link Bubbles.BubbleStateListener}.
+ *
+ * <p>If there's an existing listener, then we're switching back to stack mode and bubble views
+ * will be updated accordingly.
*/
public void unregisterBubbleStateListener() {
- mBubbleStateListener = null;
+ if (mBubbleStateListener != null) {
+ mBubbleStateListener = null;
+ setUpBubbleViewsForMode();
+ }
}
/**
@@ -646,8 +647,12 @@
/** Whether bubbles are showing in the bubble bar. */
public boolean isShowingAsBubbleBar() {
- // TODO(b/269670598): should also check that we're in gesture nav
- return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
+ return canShowAsBubbleBar() && mBubbleStateListener != null;
+ }
+
+ /** Whether the current configuration supports showing as bubble bar. */
+ private boolean canShowAsBubbleBar() {
+ return mBubbleProperties.isBubbleBarEnabled() && mBubblePositioner.isLargeScreen();
}
/** Whether this userId belongs to the current user. */
@@ -775,12 +780,12 @@
try {
mAddedToWindowManager = true;
registerBroadcastReceiver();
- mBubbleData.getOverflow().initialize(this);
+ mBubbleData.getOverflow().initialize(this, isShowingAsBubbleBar());
// (TODO: b/273314541) some duplication in the inset listener
if (isShowingAsBubbleBar()) {
mWindowManager.addView(mLayerView, mWmLayoutParams);
mLayerView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
- if (!windowInsets.equals(mWindowInsets)) {
+ if (!windowInsets.equals(mWindowInsets) && mLayerView != null) {
mWindowInsets = windowInsets;
mBubblePositioner.update();
mLayerView.onDisplaySizeChanged();
@@ -790,7 +795,7 @@
} else {
mWindowManager.addView(mStackView, mWmLayoutParams);
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
- if (!windowInsets.equals(mWindowInsets)) {
+ if (!windowInsets.equals(mWindowInsets) && mStackView != null) {
mWindowInsets = windowInsets;
mBubblePositioner.update();
mStackView.onDisplaySizeChanged();
@@ -1067,9 +1072,18 @@
* Expands and selects the provided bubble as long as it already exists in the stack or the
* overflow.
*
- * This is used by external callers (launcher).
+ * <p>This is used by external callers (launcher).
*/
- public void expandStackAndSelectBubbleFromLauncher(String key) {
+ @VisibleForTesting
+ public void expandStackAndSelectBubbleFromLauncher(String key, boolean onLauncherHome) {
+ mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
+
+ if (BubbleOverflow.KEY.equals(key)) {
+ mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
+ mLayerView.showExpandedView(mBubbleData.getOverflow());
+ return;
+ }
+
Bubble b = mBubbleData.getAnyBubbleWithkey(key);
if (b == null) {
return;
@@ -1230,10 +1244,11 @@
/**
* Performs a screenshot that may exclude the bubble layer, if one is present. The screenshot
- * can be access via the supplied {@link ScreenshotSync#get()} asynchronously.
+ * can be access via the supplied {@link SynchronousScreenCaptureListener#getBuffer()}
+ * asynchronously.
*/
public void getScreenshotExcludingBubble(int displayId,
- Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener) {
+ SynchronousScreenCaptureListener screenCaptureListener) {
try {
ScreenCapture.CaptureArgs args = null;
if (mStackView != null) {
@@ -1248,7 +1263,7 @@
}
}
- mWmService.captureDisplay(displayId, args, screenCaptureListener.first);
+ mWmService.captureDisplay(displayId, args, screenCaptureListener);
} catch (RemoteException e) {
Log.e(TAG, "Failed to capture screenshot");
}
@@ -1286,6 +1301,50 @@
});
}
+ void setUpBubbleViewsForMode() {
+ mBubbleViewCallback = isShowingAsBubbleBar()
+ ? mBubbleBarViewCallback
+ : mBubbleStackViewCallback;
+
+ // reset the overflow so that it can be re-added later if needed.
+ if (mStackView != null) {
+ mStackView.resetOverflowView();
+ mStackView.removeAllViews();
+ }
+ // cleanup existing bubble views so they can be recreated later if needed.
+ mBubbleData.getBubbles().forEach(Bubble::cleanupViews);
+
+ // remove the current bubble container from window manager, null it out, and create a new
+ // container based on the current mode.
+ removeFromWindowManagerMaybe();
+ mLayerView = null;
+ mStackView = null;
+ ensureBubbleViewsAndWindowCreated();
+
+ // inflate bubble views
+ BubbleViewInfoTask.Callback callback = null;
+ if (!isShowingAsBubbleBar()) {
+ callback = b -> {
+ if (mStackView != null) {
+ mStackView.addBubble(b);
+ mStackView.setSelectedBubble(b);
+ } else {
+ Log.w(TAG, "Tried to add a bubble to the stack but the stack is null");
+ }
+ };
+ }
+ for (int i = mBubbleData.getBubbles().size() - 1; i >= 0; i--) {
+ Bubble bubble = mBubbleData.getBubbles().get(i);
+ bubble.inflate(callback,
+ mContext,
+ this,
+ mStackView,
+ mLayerView,
+ mBubbleIconFactory,
+ false /* skipInflation */);
+ }
+ }
+
/**
* Adds or updates a bubble associated with the provided notification entry.
*
@@ -1746,7 +1805,7 @@
// Update the cached state for queries from SysUI
mImpl.mCachedState.update(update);
- if (isShowingAsBubbleBar() && mBubbleStateListener != null) {
+ if (isShowingAsBubbleBar()) {
BubbleBarUpdate bubbleBarUpdate = update.toBubbleBarUpdate();
// Some updates aren't relevant to the bubble bar so check first.
if (bubbleBarUpdate.anythingChanged()) {
@@ -1868,10 +1927,17 @@
}
@VisibleForTesting
+ @Nullable
public BubbleStackView getStackView() {
return mStackView;
}
+ @VisibleForTesting
+ @Nullable
+ public BubbleBarLayerView getLayerView() {
+ return mLayerView;
+ }
+
/**
* Check if notification panel is in an expanded state.
* Makes a call to System UI process and delivers the result via {@code callback} on the
@@ -2010,22 +2076,18 @@
@Override
public void registerBubbleListener(IBubblesListener listener) {
- mMainExecutor.execute(() -> {
- mListener.register(listener);
- });
+ mMainExecutor.execute(() -> mListener.register(listener));
}
@Override
public void unregisterBubbleListener(IBubblesListener listener) {
- mMainExecutor.execute(() -> mListener.unregister());
+ mMainExecutor.execute(mListener::unregister);
}
@Override
public void showBubble(String key, boolean onLauncherHome) {
- mMainExecutor.execute(() -> {
- mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
- mController.expandStackAndSelectBubbleFromLauncher(key);
- });
+ mMainExecutor.execute(
+ () -> mController.expandStackAndSelectBubbleFromLauncher(key, onLauncherHome));
}
@Override
@@ -2037,11 +2099,6 @@
public void collapseBubbles() {
mMainExecutor.execute(() -> mController.collapseStack());
}
-
- @Override
- public void onTaskbarStateChanged(int newState) {
- // TODO (b/269670598)
- }
}
private class BubblesImpl implements Bubbles {
@@ -2219,15 +2276,15 @@
@Override
@Nullable
- public ScreenshotSync getScreenshotExcludingBubble(int displayId) {
- Pair<ScreenCaptureListener, ScreenshotSync> screenCaptureListener =
+ public SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId) {
+ SynchronousScreenCaptureListener screenCaptureListener =
ScreenCapture.createSyncCaptureListener();
mMainExecutor.execute(
() -> BubbleController.this.getScreenshotExcludingBubble(displayId,
screenCaptureListener));
- return screenCaptureListener.second;
+ return screenCaptureListener;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index e37c785..942dcd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -33,6 +33,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
@@ -45,7 +46,7 @@
private val volatileRepository = BubbleVolatileRepository(launcherApps)
private val persistentRepository = BubblePersistentRepository(context)
- private val ioScope = CoroutineScope(Dispatchers.IO)
+ private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var job: Job? = null
// For use in Bubble construction.
@@ -131,7 +132,7 @@
*/
private fun persistToDisk() {
val prev = job
- job = ioScope.launch {
+ job = coroutineScope.launch {
// if there was an ongoing disk I/O operation, they can be cancelled
prev?.cancelAndJoin()
// check for cancellation before disk I/O
@@ -148,7 +149,7 @@
* bubbles.
*/
@SuppressLint("WrongConstant")
- fun loadBubbles(userId: Int, cb: (List<Bubble>) -> Unit) = ioScope.launch {
+ fun loadBubbles(userId: Int, cb: (List<Bubble>) -> Unit) = coroutineScope.launch {
/**
* Load BubbleEntity from disk.
* e.g.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e1a3f3a..6718565 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -948,9 +948,9 @@
mTaskView.onLocationChanged();
}
if (mIsOverflow) {
- post(() -> {
- mOverflowView.show();
- });
+ // post this to the looper so that the view has a chance to be laid out before it can
+ // calculate row and column sizes correctly.
+ post(() -> mOverflowView.show());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index df7f5b4..df19757 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -44,6 +44,7 @@
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var expandedView: BubbleExpandedView?
+ private var bubbleBarExpandedView: BubbleBarExpandedView? = null
private var overflowBtn: BadgedImageView?
init {
@@ -53,19 +54,26 @@
}
/** Call before use and again if cleanUpExpandedState was called. */
- fun initialize(controller: BubbleController) {
- createExpandedView()
- getExpandedView()?.initialize(controller, controller.stackView, true /* isOverflow */)
+ fun initialize(controller: BubbleController, forBubbleBar: Boolean) {
+ if (forBubbleBar) {
+ createBubbleBarExpandedView().initialize(controller, true /* isOverflow */)
+ } else {
+ createExpandedView()
+ .initialize(controller, controller.stackView, true /* isOverflow */)
+ }
}
fun cleanUpExpandedState() {
expandedView?.cleanUpExpandedState()
expandedView = null
+ bubbleBarExpandedView?.cleanUpExpandedState()
+ bubbleBarExpandedView = null
}
fun update() {
updateResources()
getExpandedView()?.applyThemeAttrs()
+ getBubbleBarExpandedView()?.applyThemeAttrs()
// Apply inset and new style to fresh icon drawable.
getIconView()?.setIconImageResource(R.drawable.bubble_ic_overflow_button)
updateBtnTheme()
@@ -151,26 +159,39 @@
overflowBtn?.updateDotVisibility(true /* animate */)
}
- fun createExpandedView(): BubbleExpandedView? {
- expandedView =
+ /** Creates the expanded view for bubbles showing in the stack view. */
+ private fun createExpandedView(): BubbleExpandedView {
+ val view =
inflater.inflate(
R.layout.bubble_expanded_view,
null /* root */,
false /* attachToRoot */
) as BubbleExpandedView
- expandedView?.applyThemeAttrs()
+ view.applyThemeAttrs()
+ expandedView = view
updateResources()
- return expandedView
+ return view
}
override fun getExpandedView(): BubbleExpandedView? {
return expandedView
}
- override fun getBubbleBarExpandedView(): BubbleBarExpandedView? {
- return null
+ /** Creates the expanded view for bubbles showing in the bubble bar. */
+ private fun createBubbleBarExpandedView(): BubbleBarExpandedView {
+ val view =
+ inflater.inflate(
+ R.layout.bubble_bar_expanded_view,
+ null, /* root */
+ false /* attachToRoot*/
+ ) as BubbleBarExpandedView
+ view.applyThemeAttrs()
+ bubbleBarExpandedView = view
+ return view
}
+ override fun getBubbleBarExpandedView(): BubbleBarExpandedView? = bubbleBarExpandedView
+
override fun getDotColor(): Int {
return dotColor
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index d101b0c..cb08f93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -732,17 +732,25 @@
/**
* How wide the expanded view should be when showing from the bubble bar.
*/
- public int getExpandedViewWidthForBubbleBar() {
- return mExpandedViewLargeScreenWidth;
+ public int getExpandedViewWidthForBubbleBar(boolean isOverflow) {
+ return isOverflow ? mOverflowWidth : mExpandedViewLargeScreenWidth;
}
/**
* How tall the expanded view should be when showing from the bubble bar.
*/
- public int getExpandedViewHeightForBubbleBar() {
+ public int getExpandedViewHeightForBubbleBar(boolean isOverflow) {
+ return isOverflow
+ ? mOverflowHeight
+ : getExpandedViewBottomForBubbleBar() - mInsets.top - mExpandedViewPadding;
+ }
+
+ /** The bottom position of the expanded view when showing above the bubble bar. */
+ public int getExpandedViewBottomForBubbleBar() {
return getAvailableRect().height()
+ + mInsets.top
- mBubbleBarSize
- - mExpandedViewPadding * 2
+ - mExpandedViewPadding
- getBubbleBarHomeAdjustment();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 68fea41..282db9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -88,6 +88,8 @@
import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.common.bubbles.RelativeTouchListener;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import java.io.PrintWriter;
@@ -307,6 +309,7 @@
String bubblesOnScreen = BubbleDebugConfig.formatBubblesString(
getBubblesOnScreen(), getExpandedBubble());
+ pw.print(" stack visibility : "); pw.println(getVisibility());
pw.print(" bubbles on screen: "); pw.println(bubblesOnScreen);
pw.print(" gestureInProgress: "); pw.println(mIsGestureInProgress);
pw.print(" showingDismiss: "); pw.println(mDismissView.isShowing());
@@ -968,6 +971,8 @@
mBubbleContainer.bringToFront();
mBubbleOverflow = mBubbleData.getOverflow();
+
+ resetOverflowView();
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
mBubbleContainer.getChildCount() /* index */,
new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
@@ -1179,6 +1184,7 @@
removeView(mDismissView);
}
mDismissView = new DismissView(getContext());
+ DismissViewUtils.setup(mDismissView);
int elevation = getResources().getDimensionPixelSize(R.dimen.bubble_elevation);
addView(mDismissView);
@@ -1494,9 +1500,6 @@
getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
- if (mBubbleOverflow != null) {
- mBubbleOverflow.cleanUpExpandedState();
- }
}
@Override
@@ -3411,6 +3414,19 @@
}
/**
+ * Removes the overflow view from the stack. This allows for re-adding it later to a new stack.
+ */
+ void resetOverflowView() {
+ BadgedImageView overflowIcon = mBubbleOverflow.getIconView();
+ if (overflowIcon != null) {
+ PhysicsAnimationLayout parent = (PhysicsAnimationLayout) overflowIcon.getParent();
+ if (parent != null) {
+ parent.removeViewNoAnimation(overflowIcon);
+ }
+ }
+ }
+
+ /**
* Holds some commonly queried information about the stack.
*/
public static class StackViewState {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 80e2999..66e6930 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -176,44 +176,14 @@
LayoutInflater inflater = LayoutInflater.from(c);
info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
- info.bubbleBarExpandedView.initialize(controller);
+ info.bubbleBarExpandedView.initialize(controller, false /* isOverflow */);
}
- if (b.getShortcutInfo() != null) {
- info.shortcutInfo = b.getShortcutInfo();
- }
-
- // App name & app icon
- PackageManager pm = BubbleController.getPackageManagerForUser(c,
- b.getUser().getIdentifier());
- ApplicationInfo appInfo;
- Drawable badgedIcon;
- Drawable appIcon;
- try {
- appInfo = pm.getApplicationInfo(
- b.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (appInfo != null) {
- info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
- }
- appIcon = pm.getApplicationIcon(b.getPackageName());
- badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
- } catch (PackageManager.NameNotFoundException exception) {
- // If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ if (!populateCommonInfo(info, c, b, iconFactory)) {
+ // if we failed to update common fields return null
return null;
}
- info.rawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon;
- float[] bubbleBitmapScale = new float[1];
- info.bubbleBitmap = iconFactory.getBubbleBitmap(
- iconFactory.getBubbleDrawable(c, info.shortcutInfo,
- b.getIcon()), bubbleBitmapScale);
-
-
return info;
}
@@ -236,66 +206,11 @@
info.expandedView.initialize(controller, stackView, false /* isOverflow */);
}
- if (b.getShortcutInfo() != null) {
- info.shortcutInfo = b.getShortcutInfo();
- }
-
- // App name & app icon
- PackageManager pm = BubbleController.getPackageManagerForUser(c,
- b.getUser().getIdentifier());
- ApplicationInfo appInfo;
- Drawable badgedIcon;
- Drawable appIcon;
- try {
- appInfo = pm.getApplicationInfo(
- b.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (appInfo != null) {
- info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
- }
- appIcon = pm.getApplicationIcon(b.getPackageName());
- badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
- } catch (PackageManager.NameNotFoundException exception) {
- // If we can't find package... don't think we should show the bubble.
- Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ if (!populateCommonInfo(info, c, b, iconFactory)) {
+ // if we failed to update common fields return null
return null;
}
- // Badged bubble image
- Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
- b.getIcon());
- if (bubbleDrawable == null) {
- // Default to app icon
- bubbleDrawable = appIcon;
- }
-
- BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
- b.isImportantConversation());
- info.badgeBitmap = badgeBitmapInfo.icon;
- // Raw badge bitmap never includes the important conversation ring
- info.rawBadgeBitmap = b.isImportantConversation()
- ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
- : badgeBitmapInfo.icon;
-
- float[] bubbleBitmapScale = new float[1];
- info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
-
- // Dot color & placement
- Path iconPath = PathParser.createPathFromPathData(
- c.getResources().getString(com.android.internal.R.string.config_icon_mask));
- Matrix matrix = new Matrix();
- float scale = bubbleBitmapScale[0];
- float radius = DEFAULT_PATH_SIZE / 2f;
- matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
- radius /* pivot y */);
- iconPath.transform(matrix);
- info.dotPath = iconPath;
- info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
- Color.WHITE, WHITE_SCRIM_ALPHA);
-
// Flyout
info.flyoutMessage = b.getFlyoutMessage();
if (info.flyoutMessage != null) {
@@ -306,6 +221,75 @@
}
}
+ /**
+ * Modifies the given {@code info} object and populates common fields in it.
+ *
+ * <p>This method returns {@code true} if the update was successful and {@code false} otherwise.
+ * Callers should assume that the info object is unusable if the update was unsuccessful.
+ */
+ private static boolean populateCommonInfo(
+ BubbleViewInfo info, Context c, Bubble b, BubbleIconFactory iconFactory) {
+ if (b.getShortcutInfo() != null) {
+ info.shortcutInfo = b.getShortcutInfo();
+ }
+
+ // App name & app icon
+ PackageManager pm = BubbleController.getPackageManagerForUser(c,
+ b.getUser().getIdentifier());
+ ApplicationInfo appInfo;
+ Drawable badgedIcon;
+ Drawable appIcon;
+ try {
+ appInfo = pm.getApplicationInfo(
+ b.getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (appInfo != null) {
+ info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
+ }
+ appIcon = pm.getApplicationIcon(b.getPackageName());
+ badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
+ } catch (PackageManager.NameNotFoundException exception) {
+ // If we can't find package... don't think we should show the bubble.
+ Log.w(TAG, "Unable to find package: " + b.getPackageName());
+ return false;
+ }
+
+ // Badged bubble image
+ Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, b.getIcon());
+ if (bubbleDrawable == null) {
+ // Default to app icon
+ bubbleDrawable = appIcon;
+ }
+
+ BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
+ b.isImportantConversation());
+ info.badgeBitmap = badgeBitmapInfo.icon;
+ // Raw badge bitmap never includes the important conversation ring
+ info.rawBadgeBitmap = b.isImportantConversation() // is this needed for bar?
+ ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
+ : badgeBitmapInfo.icon;
+
+ float[] bubbleBitmapScale = new float[1];
+ info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
+
+ // Dot color & placement
+ Path iconPath = PathParser.createPathFromPathData(
+ c.getResources().getString(com.android.internal.R.string.config_icon_mask));
+ Matrix matrix = new Matrix();
+ float scale = bubbleBitmapScale[0];
+ float radius = DEFAULT_PATH_SIZE / 2f;
+ matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+ radius /* pivot y */);
+ iconPath.transform(matrix);
+ info.dotPath = iconPath;
+ info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
+ Color.WHITE, WHITE_SCRIM_ALPHA);
+ return true;
+ }
+
@Nullable
static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
Objects.requireNonNull(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 259f692..759246e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.bubbles;
-import static android.window.ScreenCapture.ScreenshotSync;
-
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER;
@@ -34,6 +32,7 @@
import android.util.Pair;
import android.util.SparseArray;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -61,9 +60,11 @@
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED})
+ DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED,
+ DISMISS_SWITCH_TO_STACK})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
- @interface DismissReason {}
+ @interface DismissReason {
+ }
int DISMISS_USER_GESTURE = 1;
int DISMISS_AGED = 2;
@@ -81,6 +82,7 @@
int DISMISS_NO_BUBBLE_UP = 14;
int DISMISS_RELOAD_FROM_DISK = 15;
int DISMISS_USER_REMOVED = 16;
+ int DISMISS_SWITCH_TO_STACK = 17;
/** Returns a binder that can be passed to an external process to manipulate Bubbles. */
default IBubbles createExternalInterface() {
@@ -121,8 +123,8 @@
/**
* This method has different behavior depending on:
- * - if an app bubble exists
- * - if an app bubble is expanded
+ * - if an app bubble exists
+ * - if an app bubble is expanded
*
* If no app bubble exists, this will add and expand a bubble with the provided intent. The
* intent must be explicit (i.e. include a package name or fully qualified component class name)
@@ -136,13 +138,13 @@
* the bubble or bubble stack.
*
* Some notes:
- * - Only one app bubble is supported at a time, regardless of users. Multi-users support is
- * tracked in b/273533235.
- * - Calling this method with a different intent than the existing app bubble will do nothing
+ * - Only one app bubble is supported at a time, regardless of users. Multi-users support is
+ * tracked in b/273533235.
+ * - Calling this method with a different intent than the existing app bubble will do nothing
*
* @param intent the intent to display in the bubble expanded view.
- * @param user the {@link UserHandle} of the user to start this activity for.
- * @param icon the {@link Icon} to use for the bubble view.
+ * @param user the {@link UserHandle} of the user to start this activity for.
+ * @param icon the {@link Icon} to use for the bubble view.
*/
void showOrHideAppBubble(Intent intent, UserHandle user, @Nullable Icon icon);
@@ -150,13 +152,14 @@
boolean isAppBubbleTaskId(int taskId);
/**
- * @return a {@link ScreenshotSync} after performing a screenshot that may exclude the bubble
- * layer, if one is present. The underlying {@link ScreenshotHardwareBuffer} can be access via
- * {@link ScreenshotSync#get()} asynchronously and care should be taken to
- * {@link HardwareBuffer#close()} the associated
- * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required.
+` * @return a {@link SynchronousScreenCaptureListener} after performing a screenshot that may
+ * exclude the bubble layer, if one is present. The underlying
+ * {@link ScreenshotHardwareBuffer} can be accessed via
+ * {@link SynchronousScreenCaptureListener#getBuffer()} asynchronously and care should be taken
+ * to {@link HardwareBuffer#close()} the associated
+ * {@link ScreenshotHardwareBuffer#getHardwareBuffer()} when no longer required.`
*/
- ScreenshotSync getScreenshotExcludingBubble(int displayId);
+ SynchronousScreenCaptureListener getScreenshotExcludingBubble(int displayId);
/**
* @return a bubble that matches the provided shortcutId, if one exists.
@@ -172,13 +175,12 @@
* {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
* {@link BubbleData#addSummaryToSuppress}.
*
- * @param entry the notification of the BubbleEntry should be removed.
- * @param children the list of child notification of the BubbleEntry from 1st param entry,
- * this will be null if entry does have no children.
+ * @param entry the notification of the BubbleEntry should be removed.
+ * @param children the list of child notification of the BubbleEntry from 1st param entry,
+ * this will be null if entry does have no children.
* @param removeCallback the remove callback for SystemUI side to remove notification, the int
* number should be list position of children list and use -1 for
* removing the parent notification.
- *
* @return true if we want to intercept the dismissal of the entry, else false.
*/
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
@@ -200,9 +202,9 @@
/**
* Called when new notification entry updated.
*
- * @param entry the {@link BubbleEntry} by the notification.
+ * @param entry the {@link BubbleEntry} by the notification.
* @param shouldBubbleUp {@code true} if this notification should bubble up.
- * @param fromSystem {@code true} if this update is from NotificationManagerService.
+ * @param fromSystem {@code true} if this update is from NotificationManagerService.
*/
void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem);
@@ -218,7 +220,7 @@
* filtering and sorting. This is used to dismiss or create bubbles based on changes in
* permissions on the notification channel or the global setting.
*
- * @param rankingMap the updated ranking map from NotificationListenerService
+ * @param rankingMap the updated ranking map from NotificationListenerService
* @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
* bubble up
*/
@@ -230,9 +232,9 @@
* Called when a notification channel is modified, in response to
* {@link NotificationListenerService#onNotificationChannelModified}.
*
- * @param pkg the package the notification channel belongs to.
- * @param user the user the notification channel belongs to.
- * @param channel the channel being modified.
+ * @param pkg the package the notification channel belongs to.
+ * @param user the user the notification channel belongs to.
+ * @param channel the channel being modified.
* @param modificationType the type of modification that occurred to the channel.
*/
void onNotificationChannelModified(
@@ -300,7 +302,7 @@
* Called when the expansion state of the bubble stack changes.
*
* @param isExpanding whether it's expanding or collapsing
- * @param key the notification key associated with bubble being expanded
+ * @param key the notification key associated with bubble being expanded
*/
void onBubbleExpandChanged(boolean isExpanding, String key);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
deleted file mode 100644
index 67ecb91..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ /dev/null
@@ -1,159 +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.bubbles
-
-import android.animation.ObjectAnimator
-import android.content.Context
-import android.graphics.Color
-import android.graphics.drawable.GradientDrawable
-import android.util.IntProperty
-import android.view.Gravity
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowInsets
-import android.view.WindowManager
-import android.widget.FrameLayout
-import androidx.dynamicanimation.animation.DynamicAnimation
-import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
-import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
-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.
- */
-class DismissView(context: Context) : FrameLayout(context) {
-
- var circle = DismissCircleView(context)
- var isShowing = false
- var targetSizeResId: Int
-
- private val animator = PhysicsAnimator.getInstance(circle)
- private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
- private val DISMISS_SCRIM_FADE_MS = 200L
- private var wm: WindowManager =
- context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- private var gradientDrawable = createGradient()
-
- private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
- object : IntProperty<GradientDrawable>("alpha") {
- override fun setValue(d: GradientDrawable, percent: Int) {
- d.alpha = percent
- }
- override fun get(d: GradientDrawable): Int {
- return d.alpha
- }
- }
-
- init {
- setLayoutParams(LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
- Gravity.BOTTOM))
- updatePadding()
- setClipToPadding(false)
- setClipChildren(false)
- setVisibility(View.INVISIBLE)
- setBackgroundDrawable(gradientDrawable)
-
- targetSizeResId = R.dimen.dismiss_circle_size
- val targetSize: Int = resources.getDimensionPixelSize(targetSizeResId)
- addView(circle, LayoutParams(targetSize, targetSize,
- Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL))
- // start with circle offscreen so it's animated up
- circle.setTranslationY(resources.getDimensionPixelSize(
- R.dimen.floating_dismiss_gradient_height).toFloat())
- }
-
- /**
- * Animates this view in.
- */
- fun show() {
- if (isShowing) return
- isShowing = true
- setVisibility(View.VISIBLE)
- val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
- gradientDrawable.alpha, 255)
- alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
- alphaAnim.start()
-
- animator.cancel()
- animator
- .spring(DynamicAnimation.TRANSLATION_Y, 0f, spring)
- .start()
- }
-
- /**
- * Animates this view out, as well as the circle that encircles the bubbles, if they
- * were dragged into the target and encircled.
- */
- fun hide() {
- if (!isShowing) return
- isShowing = false
- val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
- gradientDrawable.alpha, 0)
- alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
- alphaAnim.start()
- animator
- .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(),
- spring)
- .withEndActions({ setVisibility(View.INVISIBLE) })
- .start()
- }
-
- /**
- * Cancels the animator for the dismiss target.
- */
- fun cancelAnimators() {
- animator.cancel()
- }
-
- fun updateResources() {
- updatePadding()
- layoutParams.height = resources.getDimensionPixelSize(
- R.dimen.floating_dismiss_gradient_height)
-
- val targetSize = resources.getDimensionPixelSize(targetSizeResId)
- circle.layoutParams.width = targetSize
- circle.layoutParams.height = targetSize
- circle.requestLayout()
- }
-
- private fun createGradient(): GradientDrawable {
- val gradientColor = context.resources.getColor(android.R.color.system_neutral1_900)
- val alpha = 0.7f * 255
- val gradientColorWithAlpha = Color.argb(alpha.toInt(),
- Color.red(gradientColor),
- Color.green(gradientColor),
- Color.blue(gradientColor))
- val gd = GradientDrawable(
- GradientDrawable.Orientation.BOTTOM_TOP,
- intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT))
- gd.setDither(true)
- gd.setAlpha(0)
- return gd
- }
-
- private fun updatePadding() {
- val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
- val navInset = insets.getInsetsIgnoringVisibility(
- WindowInsets.Type.navigationBars())
- setPadding(0, 0, 0, navInset.bottom +
- resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin))
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt
new file mode 100644
index 0000000..ed36240
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissViewExt.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("DismissViewUtils")
+
+package com.android.wm.shell.bubbles
+
+import com.android.wm.shell.R
+import com.android.wm.shell.common.bubbles.DismissView
+
+fun DismissView.setup() {
+ setup(DismissView.Config(
+ targetSizeResId = R.dimen.dismiss_circle_size,
+ iconSizeResId = R.dimen.dismiss_target_x_size,
+ bottomMarginResId = R.dimen.floating_dismiss_bottom_margin,
+ floatingGradientHeightResId = R.dimen.floating_dismiss_gradient_height,
+ floatingGradientColorResId = android.R.color.system_neutral1_900,
+ backgroundResId = R.drawable.dismiss_circle_background,
+ iconResId = R.drawable.pip_ic_close_white
+ ))
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 862e818..20ae846 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -35,6 +35,4 @@
oneway void collapseBubbles() = 5;
- oneway void onTaskbarStateChanged(in int newState) = 6;
-
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index 55052e6..f3cc514 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -327,6 +327,12 @@
addViewInternal(child, index, params, false /* isReorder */);
}
+ /** Removes the child view immediately. */
+ public void removeViewNoAnimation(View view) {
+ super.removeView(view);
+ view.setTag(R.id.physics_animator_tag, null);
+ }
+
@Override
public void removeView(View view) {
if (mController != null) {
@@ -523,6 +529,7 @@
*/
@Nullable private SpringAnimation getSpringAnimationFromView(
DynamicAnimation.ViewProperty property, View view) {
+ if (view == null) return null;
return (SpringAnimation) view.getTag(getTagIdForProperty(property));
}
@@ -531,11 +538,13 @@
* system.
*/
@Nullable private ViewPropertyAnimator getViewPropertyAnimatorFromView(View view) {
+ if (view == null) return null;
return (ViewPropertyAnimator) view.getTag(R.id.reorder_animator_tag);
}
/** Retrieves the target animator from the view via the view tag system. */
@Nullable private ObjectAnimator getTargetAnimatorFromView(View view) {
+ if (view == null) return null;
return (ObjectAnimator) view.getTag(R.id.target_animator_tag);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 23f65f9..f729d02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -27,6 +27,7 @@
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
@@ -215,9 +216,10 @@
}
BubbleBarExpandedView bbev = mExpandedBubble.getBubbleBarExpandedView();
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bbev.getLayoutParams();
lp.width = width;
lp.height = height;
@@ -227,7 +229,8 @@
} else {
bbev.setX(mPositioner.getAvailableRect().width() - width - padding);
}
- bbev.setY(mPositioner.getInsets().top + padding);
+ bbev.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
bbev.updateLocation();
+ bbev.maybeShowOverflow();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 32ed102..396aa0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -25,6 +25,7 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
@@ -33,6 +34,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleOverflowContainerView;
import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.taskview.TaskView;
@@ -51,6 +53,7 @@
private static final int INVALID_TASK_ID = -1;
private BubbleController mController;
+ private boolean mIsOverflow;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
private @Nullable Supplier<Rect> mLayerBoundsSupplier;
@@ -58,6 +61,7 @@
private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
private @Nullable TaskView mTaskView;
+ private @Nullable BubbleOverflowContainerView mOverflowView;
private int mHandleHeight;
private int mBackgroundColor;
@@ -114,15 +118,25 @@
}
/** Set the BubbleController on the view, must be called before doing anything else. */
- public void initialize(BubbleController controller) {
+ public void initialize(BubbleController controller, boolean isOverflow) {
mController = controller;
- mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, mController,
- /* listener= */ this,
- /* viewParent= */ this);
- mTaskView = mBubbleTaskViewHelper.getTaskView();
- addView(mTaskView);
- mTaskView.setEnableSurfaceClipping(true);
- mTaskView.setCornerRadius(mCornerRadius);
+ mIsOverflow = isOverflow;
+
+ if (mIsOverflow) {
+ mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate(
+ R.layout.bubble_overflow_container, null /* root */);
+ mOverflowView.setBubbleController(mController);
+ addView(mOverflowView);
+ } else {
+
+ mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, mController,
+ /* listener= */ this,
+ /* viewParent= */ this);
+ mTaskView = mBubbleTaskViewHelper.getTaskView();
+ addView(mTaskView);
+ mTaskView.setEnableSurfaceClipping(true);
+ mTaskView.setCornerRadius(mCornerRadius);
+ }
mMenuViewController = new BubbleBarMenuViewController(mContext, this);
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@Override
@@ -156,7 +170,8 @@
}
// TODO (b/275087636): call this when theme/config changes
- void applyThemeAttrs() {
+ /** Updates the view based on the current theme. */
+ public void applyThemeAttrs() {
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources());
final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
@@ -257,8 +272,18 @@
* Call when the location or size of the view has changed to update TaskView.
*/
public void updateLocation() {
- if (mTaskView == null) return;
- mTaskView.onLocationChanged();
+ if (mTaskView != null) {
+ mTaskView.onLocationChanged();
+ }
+ }
+
+ /** Shows the expanded view for the overflow if it exists. */
+ void maybeShowOverflow() {
+ if (mOverflowView != null) {
+ // post this to the looper so that the view has a chance to be laid out before it can
+ // calculate row and column sizes correctly.
+ post(() -> mOverflowView.show());
+ }
}
/** Sets the alpha of the task view. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bc622e7..d20b33e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -29,6 +29,7 @@
import android.widget.FrameLayout;
import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
@@ -146,8 +147,9 @@
if (mExpandedView == null) {
mExpandedBubble = b;
mExpandedView = expandedView;
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ boolean isOverflowExpanded = b.getKey().equals(BubbleOverflow.KEY);
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
mExpandedView.setVisibility(GONE);
mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
@@ -156,6 +158,7 @@
mUnBubbleConversationCallback.accept(bubbleKey);
}
});
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
@@ -184,9 +187,10 @@
/** Updates the expanded view size and position. */
private void updateExpandedView() {
if (mExpandedView == null) return;
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar();
- final int height = mPositioner.getExpandedViewHeightForBubbleBar();
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
FrameLayout.LayoutParams lp = (LayoutParams) mExpandedView.getLayoutParams();
lp.width = width;
lp.height = height;
@@ -196,7 +200,7 @@
} else {
mExpandedView.setX(mPositioner.getAvailableRect().width() - width - padding);
}
- mExpandedView.setY(mPositioner.getInsets().top + padding);
+ mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
mExpandedView.updateLocation();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt
new file mode 100644
index 0000000..85aaa8e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.properties
+
+/**
+ * An interface for exposing bubble properties via flags which can be controlled easily in tests.
+ */
+interface BubbleProperties {
+ /**
+ * Whether bubble bar is enabled.
+ *
+ * When this is `true`, depending on additional factors, such as screen size and taskbar state,
+ * bubbles will be displayed in the bubble bar instead of floating.
+ *
+ * When this is `false`, bubbles will be floating.
+ */
+ val isBubbleBarEnabled: Boolean
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
new file mode 100644
index 0000000..9d8b9a6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.properties
+
+import android.os.SystemProperties
+
+/** Provides bubble properties in production. */
+object ProdBubbleProperties : BubbleProperties {
+
+ // TODO(b/256873975) Should use proper flag when available to shell/launcher
+ override val isBubbleBarEnabled =
+ SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
deleted file mode 100644
index e0c782d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DismissCircleView.java
+++ /dev/null
@@ -1,64 +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.common;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.view.Gravity;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.wm.shell.R;
-
-/**
- * Circular view with a semitransparent, circular background with an 'X' inside it.
- *
- * This is used by both Bubbles and PIP as the dismiss target.
- */
-public class DismissCircleView extends FrameLayout {
-
- private final ImageView mIconView = new ImageView(getContext());
-
- public DismissCircleView(Context context) {
- super(context);
- final Resources res = getResources();
-
- setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
-
- mIconView.setImageDrawable(res.getDrawable(R.drawable.pip_ic_close_white));
- addView(mIconView);
-
- setViewSizes();
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- final Resources res = getResources();
- setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
- setViewSizes();
- }
-
- /** Retrieves the current dimensions for the icon and circle and applies them. */
- private void setViewSizes() {
- final Resources res = getResources();
- final int iconSize = res.getDimensionPixelSize(R.dimen.dismiss_target_x_size);
- mIconView.setLayoutParams(
- new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java
new file mode 100644
index 0000000..7c5bb21
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissCircleView.java
@@ -0,0 +1,76 @@
+/*
+ * 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.bubbles;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.annotation.DimenRes;
+import androidx.annotation.DrawableRes;
+import androidx.core.content.ContextCompat;
+
+/**
+ * Circular view with a semitransparent, circular background with an 'X' inside it.
+ *
+ * This is used by both Bubbles and PIP as the dismiss target.
+ */
+public class DismissCircleView extends FrameLayout {
+ @DrawableRes int mBackgroundResId;
+ @DimenRes int mIconSizeResId;
+
+ private final ImageView mIconView = new ImageView(getContext());
+
+ public DismissCircleView(Context context) {
+ super(context);
+ addView(mIconView);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setBackground(ContextCompat.getDrawable(getContext(), mBackgroundResId));
+ setViewSizes();
+ }
+
+ /**
+ * Sets up view with the provided resource ids.
+ * Decouples resource dependency in order to be used externally (e.g. Launcher)
+ *
+ * @param backgroundResId drawable resource id of the circle background
+ * @param iconResId drawable resource id of the icon for the dismiss view
+ * @param iconSizeResId dimen resource id of the icon size
+ */
+ public void setup(@DrawableRes int backgroundResId, @DrawableRes int iconResId,
+ @DimenRes int iconSizeResId) {
+ mBackgroundResId = backgroundResId;
+ mIconSizeResId = iconSizeResId;
+
+ setBackground(ContextCompat.getDrawable(getContext(), backgroundResId));
+ mIconView.setImageDrawable(ContextCompat.getDrawable(getContext(), iconResId));
+ setViewSizes();
+ }
+
+ /** Retrieves the current dimensions for the icon and circle and applies them. */
+ private void setViewSizes() {
+ final int iconSize = getResources().getDimensionPixelSize(mIconSizeResId);
+ mIconView.setLayoutParams(
+ new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt
new file mode 100644
index 0000000..d275a0b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/DismissView.kt
@@ -0,0 +1,222 @@
+/*
+ * 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.bubbles
+
+import android.animation.ObjectAnimator
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.util.IntProperty
+import android.util.Log
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.widget.FrameLayout
+import androidx.annotation.ColorRes
+import androidx.annotation.DimenRes
+import androidx.annotation.DrawableRes
+import androidx.core.content.ContextCompat
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
+import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
+import com.android.wm.shell.animation.PhysicsAnimator
+
+/**
+ * View that handles interactions between DismissCircleView and BubbleStackView.
+ *
+ * @note [setup] method should be called after initialisation
+ */
+class DismissView(context: Context) : FrameLayout(context) {
+ /**
+ * The configuration is used to provide module specific resource ids
+ *
+ * @see [setup] method
+ */
+ data class Config(
+ /** dimen resource id of the dismiss target circle view size */
+ @DimenRes val targetSizeResId: Int,
+ /** dimen resource id of the icon size in the dismiss target */
+ @DimenRes val iconSizeResId: Int,
+ /** dimen resource id of the bottom margin for the dismiss target */
+ @DimenRes var bottomMarginResId: Int,
+ /** dimen resource id of the height for dismiss area gradient */
+ @DimenRes val floatingGradientHeightResId: Int,
+ /** color resource id of the dismiss area gradient color */
+ @ColorRes val floatingGradientColorResId: Int,
+ /** drawable resource id of the dismiss target background */
+ @DrawableRes val backgroundResId: Int,
+ /** drawable resource id of the icon for the dismiss target */
+ @DrawableRes val iconResId: Int
+ )
+
+ companion object {
+ private const val SHOULD_SETUP =
+ "The view isn't ready. Should be called after `setup`"
+ private val TAG = DismissView::class.simpleName
+ }
+
+ var circle = DismissCircleView(context)
+ var isShowing = false
+ var config: Config? = null
+
+ private val animator = PhysicsAnimator.getInstance(circle)
+ private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
+ private val DISMISS_SCRIM_FADE_MS = 200L
+ private var wm: WindowManager =
+ context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ private var gradientDrawable: GradientDrawable? = null
+
+ private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
+ object : IntProperty<GradientDrawable>("alpha") {
+ override fun setValue(d: GradientDrawable, percent: Int) {
+ d.alpha = percent
+ }
+ override fun get(d: GradientDrawable): Int {
+ return d.alpha
+ }
+ }
+
+ init {
+ setClipToPadding(false)
+ setClipChildren(false)
+ setVisibility(View.INVISIBLE)
+ addView(circle)
+ }
+
+ /**
+ * Sets up view with the provided resource ids.
+ *
+ * Decouples resource dependency in order to be used externally (e.g. Launcher). Usually called
+ * with default params in module specific extension:
+ * @see [DismissView.setup] in DismissViewExt.kt
+ */
+ fun setup(config: Config) {
+ this.config = config
+
+ // Setup layout
+ layoutParams = LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ resources.getDimensionPixelSize(config.floatingGradientHeightResId),
+ Gravity.BOTTOM)
+ updatePadding()
+
+ // Setup gradient
+ gradientDrawable = createGradient(color = config.floatingGradientColorResId)
+ setBackgroundDrawable(gradientDrawable)
+
+ // Setup DismissCircleView
+ circle.setup(config.backgroundResId, config.iconResId, config.iconSizeResId)
+ val targetSize: Int = resources.getDimensionPixelSize(config.targetSizeResId)
+ circle.layoutParams = LayoutParams(targetSize, targetSize,
+ Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
+ // Initial position with circle offscreen so it's animated up
+ circle.translationY = resources.getDimensionPixelSize(config.floatingGradientHeightResId)
+ .toFloat()
+ }
+
+ /**
+ * Animates this view in.
+ */
+ fun show() {
+ if (isShowing) return
+ val gradientDrawable = checkExists(gradientDrawable) ?: return
+ isShowing = true
+ setVisibility(View.VISIBLE)
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 255)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
+
+ animator.cancel()
+ animator
+ .spring(DynamicAnimation.TRANSLATION_Y, 0f, spring)
+ .start()
+ }
+
+ /**
+ * Animates this view out, as well as the circle that encircles the bubbles, if they
+ * were dragged into the target and encircled.
+ */
+ fun hide() {
+ if (!isShowing) return
+ val gradientDrawable = checkExists(gradientDrawable) ?: return
+ isShowing = false
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 0)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
+ animator
+ .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(),
+ spring)
+ .withEndActions({ setVisibility(View.INVISIBLE) })
+ .start()
+ }
+
+ /**
+ * Cancels the animator for the dismiss target.
+ */
+ fun cancelAnimators() {
+ animator.cancel()
+ }
+
+ fun updateResources() {
+ val config = checkExists(config) ?: return
+ updatePadding()
+ layoutParams.height = resources.getDimensionPixelSize(config.floatingGradientHeightResId)
+ val targetSize = resources.getDimensionPixelSize(config.targetSizeResId)
+ circle.layoutParams.width = targetSize
+ circle.layoutParams.height = targetSize
+ circle.requestLayout()
+ }
+
+ private fun createGradient(@ColorRes color: Int): GradientDrawable {
+ val gradientColor = ContextCompat.getColor(context, color)
+ val alpha = 0.7f * 255
+ val gradientColorWithAlpha = Color.argb(alpha.toInt(),
+ Color.red(gradientColor),
+ Color.green(gradientColor),
+ Color.blue(gradientColor))
+ val gd = GradientDrawable(
+ GradientDrawable.Orientation.BOTTOM_TOP,
+ intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT))
+ gd.setDither(true)
+ gd.setAlpha(0)
+ return gd
+ }
+
+ private fun updatePadding() {
+ val config = checkExists(config) ?: return
+ val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
+ val navInset = insets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.navigationBars())
+ setPadding(0, 0, 0, navInset.bottom +
+ resources.getDimensionPixelSize(config.bottomMarginResId))
+ }
+
+ /**
+ * Checks if the value is set up and exists, if not logs an exception.
+ * Used for convenient logging in case `setup` wasn't called before
+ *
+ * @return value provided as argument
+ */
+ private fun <T>checkExists(value: T?): T? {
+ if (value == null) Log.e(TAG, SHOULD_SETUP)
+ return value
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt
similarity index 98%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt
index ea9d065..cc37bd3a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.bubbles
+package com.android.wm.shell.common.bubbles
import android.graphics.PointF
import android.view.MotionEvent
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index ec40244..03f92aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -36,6 +36,7 @@
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.bubbles.properties.ProdBubbleProperties;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
@@ -64,7 +65,6 @@
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
-import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
@@ -188,7 +188,7 @@
statusBarService, windowManager, windowManagerShellWrapper, userManager,
launcherApps, logger, taskStackListener, organizer, positioner, displayController,
oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
- taskViewTransitions, syncQueue, wmService);
+ taskViewTransitions, syncQueue, wmService, ProdBubbleProperties.INSTANCE);
}
//
@@ -220,12 +220,12 @@
desktopTasksController);
}
return new CaptionWindowDecorViewModel(
- context,
- mainHandler,
- mainChoreographer,
- taskOrganizer,
- displayController,
- syncQueue);
+ context,
+ mainHandler,
+ mainChoreographer,
+ taskOrganizer,
+ displayController,
+ syncQueue);
}
//
@@ -547,10 +547,11 @@
KeyguardTransitionHandler keyguardTransitionHandler,
Optional<DesktopModeController> desktopModeController,
Optional<DesktopTasksController> desktopTasksController,
+ Optional<UnfoldTransitionHandler> unfoldHandler,
Transitions transitions) {
return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler,
- desktopModeController, desktopTasksController);
+ desktopModeController, desktopTasksController, unfoldHandler);
}
@WMSingleton
@@ -584,13 +585,13 @@
animators.add(fullscreenAnimator);
return new UnfoldAnimationController(
- shellInit,
- transactionPool,
- progressProvider.get(),
- animators,
- unfoldTransitionHandler,
- mainExecutor
- );
+ shellInit,
+ transactionPool,
+ progressProvider.get(),
+ animators,
+ unfoldTransitionHandler,
+ mainExecutor
+ );
}
@Provides
@@ -734,28 +735,6 @@
}
//
- // Kids mode
- //
- @WMSingleton
- @Provides
- static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasksOptional,
- @ShellMainThread ShellExecutor mainExecutor,
- @ShellMainThread Handler mainHandler
- ) {
- return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler,
- syncTransactionQueue, displayController, displayInsetsController,
- unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler);
- }
-
- //
// Misc
//
@@ -766,7 +745,6 @@
@Provides
static Object provideIndependentShellComponentsToCreate(
DefaultMixedHandler defaultMixedHandler,
- KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<DesktopModeController> desktopModeController) {
return new Object();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index d016e73c..65a35b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -33,6 +33,7 @@
import android.os.SystemProperties
import android.util.DisplayMetrics.DENSITY_DEFAULT
import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
@@ -267,16 +268,24 @@
*/
fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
KtProtoLog.v(
- WM_SHELL_DESKTOP_MODE,
- "DesktopTasksController: cancelMoveToFreeform taskId=%d",
- task.taskId
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: cancelMoveToFreeform taskId=%d",
+ task.taskId
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task)
+ wct.setBounds(task.token, null)
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, position,
- mOnAnimationFinishedCallback)
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(
+ wct, position) { t ->
+ val callbackWCT = WindowContainerTransaction()
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ addMoveToFullscreenChanges(callbackWCT, task)
+ shellTaskOrganizer.applyTransaction(callbackWCT)
+ }
} else {
+ addMoveToFullscreenChanges(wct, task)
shellTaskOrganizer.applyTransaction(wct)
releaseVisualIndicator()
}
@@ -500,36 +509,62 @@
request
)
// Check if we should skip handling this transition
+ var reason = ""
val shouldHandleRequest =
when {
// Only handle open or to front transitions
- request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> false
+ request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
+ reason = "transition type not handled (${request.type})"
+ false
+ }
// Only handle when it is a task transition
- request.triggerTask == null -> false
+ request.triggerTask == null -> {
+ reason = "triggerTask is null"
+ false
+ }
// Only handle standard type tasks
- request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> false
+ request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> {
+ reason = "activityType not handled (${request.triggerTask.activityType})"
+ false
+ }
// Only handle fullscreen or freeform tasks
request.triggerTask.windowingMode != WINDOWING_MODE_FULLSCREEN &&
- request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> false
+ request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> {
+ reason = "windowingMode not handled (${request.triggerTask.windowingMode})"
+ false
+ }
// Otherwise process it
else -> true
}
if (!shouldHandleRequest) {
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: skipping handleRequest reason=%s",
+ reason
+ )
return null
}
val task: RunningTaskInfo = request.triggerTask
- return when {
+ val result = when {
// If display has tasks stashed, handle as stashed launch
desktopModeTaskRepository.isStashed(task.displayId) -> handleStashedTaskLaunch(task)
// Check if fullscreen task should be updated
task.windowingMode == WINDOWING_MODE_FULLSCREEN -> handleFullscreenTaskLaunch(task)
// Check if freeform task should be updated
task.windowingMode == WINDOWING_MODE_FREEFORM -> handleFreeformTaskLaunch(task)
- else -> null
+ else -> {
+ null
+ }
}
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: handleRequest result=%s",
+ result ?: "null"
+ )
+ return result
}
/**
@@ -552,6 +587,7 @@
}
private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch")
val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
KtProtoLog.d(
@@ -568,6 +604,7 @@
}
private fun handleFullscreenTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? {
+ KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFullscreenTaskLaunch")
val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)
if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
KtProtoLog.d(
@@ -926,7 +963,7 @@
companion object {
private val DESKTOP_DENSITY_OVERRIDE =
- SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0)
+ SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284)
private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
// Override default freeform task width when desktop mode is enabled. In dips.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 3733b91..3e175f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -200,7 +199,7 @@
}
if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
&& mPosition != null) {
// This Transition animates a task to fullscreen after being dragged from the status
// bar and then released back into the status bar area
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index cef7e16..56bd188 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -156,6 +156,8 @@
"start keyguard %s transition, info = %s", description, info);
try {
+ mStartedTransitions.put(transition,
+ new StartedTransition(info, finishTransaction, remoteHandler));
remoteHandler.startAnimation(transition, info, startTransaction,
new IRemoteTransitionFinishedCallback.Stub() {
@Override
@@ -164,14 +166,13 @@
if (sct != null) {
finishTransaction.merge(sct);
}
- mMainExecutor.execute(() -> {
+ // Post our finish callback to let startAnimation finish first.
+ mMainExecutor.executeDelayed(() -> {
mStartedTransitions.remove(transition);
finishCallback.onTransitionFinished(wct, null);
- });
+ }, 0);
}
});
- mStartedTransitions.put(transition,
- new StartedTransition(info, finishTransaction, remoteHandler));
} catch (RemoteException e) {
Log.wtf(TAG, "RemoteException thrown from local IRemoteTransition", e);
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
deleted file mode 100644
index 65cb7ac..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.kidsmode;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import java.util.Collection;
-
-/**
- * A ContentObserver for listening kids mode relative setting keys:
- * - {@link Settings.Secure#NAVIGATION_MODE}
- * - {@link Settings.Secure#NAV_BAR_KIDS_MODE}
- *
- * @hide
- */
-public class KidsModeSettingsObserver extends ContentObserver {
- private Context mContext;
- private Runnable mOnChangeRunnable;
-
- public KidsModeSettingsObserver(Handler handler, Context context) {
- super(handler);
- mContext = context;
- }
-
- public void setOnChangeRunnable(Runnable r) {
- mOnChangeRunnable = r;
- }
-
- /**
- * Registers the observer.
- */
- public void register() {
- final ContentResolver r = mContext.getContentResolver();
- r.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.NAVIGATION_MODE),
- false, this, UserHandle.USER_ALL);
- r.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE),
- false, this, UserHandle.USER_ALL);
- }
-
- /**
- * Unregisters the observer.
- */
- public void unregister() {
- mContext.getContentResolver().unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags, int userId) {
- if (userId != ActivityManager.getCurrentUser()) {
- return;
- }
-
- if (mOnChangeRunnable != null) {
- mOnChangeRunnable.run();
- }
- }
-
- /**
- * Returns true only when it's in three button nav mode and the kid nav bar mode is enabled.
- * Otherwise, return false.
- */
- public boolean isEnabled() {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAVIGATION_MODE, 0, UserHandle.USER_CURRENT) == 0
- && Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAV_BAR_KIDS_MODE, 0, UserHandle.USER_CURRENT) == 1;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
deleted file mode 100644
index 6d46a9c..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.kidsmode;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.view.Display;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.WindowInsets;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.unfold.UnfoldAnimationController;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * A dedicated task organizer when kids mode is enabled.
- * - Creates a root task with bounds that exclude the navigation bar area
- * - Launch all task into the root task except for Launcher
- */
-public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
- private static final String TAG = "KidsModeTaskOrganizer";
-
- private static final int[] CONTROLLED_ACTIVITY_TYPES =
- {ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_HOME};
- private static final int[] CONTROLLED_WINDOWING_MODES =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
-
- private final Handler mMainHandler;
- private final Context mContext;
- private final ShellCommandHandler mShellCommandHandler;
- private final SyncTransactionQueue mSyncQueue;
- private final DisplayController mDisplayController;
- private final DisplayInsetsController mDisplayInsetsController;
-
- /**
- * The value of the {@link R.bool.config_reverseDefaultRotation} property which defines how
- * {@link Display#getRotation} values are mapped to screen orientations
- */
- private final boolean mReverseDefaultRotationEnabled;
-
- @VisibleForTesting
- ActivityManager.RunningTaskInfo mLaunchRootTask;
- @VisibleForTesting
- SurfaceControl mLaunchRootLeash;
- @VisibleForTesting
- final IBinder mCookie = new Binder();
-
- private final InsetsState mInsetsState = new InsetsState();
- private int mDisplayWidth;
- private int mDisplayHeight;
-
- private KidsModeSettingsObserver mKidsModeSettingsObserver;
- private boolean mEnabled;
-
- private ActivityManager.RunningTaskInfo mHomeTask;
-
- private final BroadcastReceiver mUserSwitchIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateKidsModeState();
- }
- };
-
- DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
- new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- final DisplayLayout displayLayout =
- mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
- if (displayLayout == null) {
- return;
- }
- final int displayWidth = displayLayout.width();
- final int displayHeight = displayLayout.height();
- if (displayWidth == mDisplayWidth || displayHeight == mDisplayHeight) {
- return;
- }
- mDisplayWidth = displayWidth;
- mDisplayHeight = displayHeight;
- updateBounds();
- }
- };
-
- DisplayInsetsController.OnInsetsChangedListener mOnInsetsChangedListener =
- new DisplayInsetsController.OnInsetsChangedListener() {
- @Override
- public void insetsChanged(InsetsState insetsState) {
- final boolean[] navigationBarChanged = {false};
- InsetsState.traverse(insetsState, mInsetsState, new InsetsState.OnTraverseCallbacks() {
- @Override
- public void onIdMatch(InsetsSource source1, InsetsSource source2) {
- if (source1.getType() == WindowInsets.Type.navigationBars()
- && !source1.equals(source2)) {
- navigationBarChanged[0] = true;
- }
- }
-
- @Override
- public void onIdNotFoundInState1(int index2, InsetsSource source2) {
- if (source2.getType() == WindowInsets.Type.navigationBars()) {
- navigationBarChanged[0] = true;
- }
- }
-
- @Override
- public void onIdNotFoundInState2(int index1, InsetsSource source1) {
- if (source1.getType() == WindowInsets.Type.navigationBars()) {
- navigationBarChanged[0] = true;
- }
- }
- });
- if (!navigationBarChanged[0]) {
- return;
- }
- // Update bounds only when the insets of navigation bar or task bar is changed.
- mInsetsState.set(insetsState);
- updateBounds();
- }
- };
-
- @VisibleForTesting
- KidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- ITaskOrganizerController taskOrganizerController,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasks,
- KidsModeSettingsObserver kidsModeSettingsObserver,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
- // Note: we don't call super with the shell init because we will be initializing manually
- super(/* shellInit= */ null, /* shellCommandHandler= */ null, taskOrganizerController,
- /* compatUI= */ null, unfoldAnimationController, recentTasks, mainExecutor);
- mContext = context;
- mShellCommandHandler = shellCommandHandler;
- mMainHandler = mainHandler;
- mSyncQueue = syncTransactionQueue;
- mDisplayController = displayController;
- mDisplayInsetsController = displayInsetsController;
- mKidsModeSettingsObserver = kidsModeSettingsObserver;
- shellInit.addInitCallback(this::onInit, this);
- mReverseDefaultRotationEnabled = context.getResources().getBoolean(
- R.bool.config_reverseDefaultRotation);
- }
-
- public KidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasks,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
- // Note: we don't call super with the shell init because we will be initializing manually
- super(/* shellInit= */ null, /* taskOrganizerController= */ null, /* compatUI= */ null,
- unfoldAnimationController, recentTasks, mainExecutor);
- mContext = context;
- mShellCommandHandler = shellCommandHandler;
- mMainHandler = mainHandler;
- mSyncQueue = syncTransactionQueue;
- mDisplayController = displayController;
- mDisplayInsetsController = displayInsetsController;
- shellInit.addInitCallback(this::onInit, this);
- mReverseDefaultRotationEnabled = context.getResources().getBoolean(
- R.bool.config_reverseDefaultRotation);
- }
-
- /**
- * Initializes kids mode status.
- */
- public void onInit() {
- if (mShellCommandHandler != null) {
- mShellCommandHandler.addDumpCallback(this::dump, this);
- }
- if (mKidsModeSettingsObserver == null) {
- mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext);
- }
- mKidsModeSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
- updateKidsModeState();
- mKidsModeSettingsObserver.register();
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiverForAllUsers(mUserSwitchIntentReceiver, filter, null, mMainHandler);
- }
-
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mEnabled && mLaunchRootTask == null && taskInfo.launchCookies != null
- && taskInfo.launchCookies.contains(mCookie)) {
- mLaunchRootTask = taskInfo;
- mLaunchRootLeash = leash;
- updateTask();
- }
- super.onTaskAppeared(taskInfo, leash);
-
- // Only allow home to draw under system bars.
- if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- wct.setBounds(taskInfo.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
- mSyncQueue.queue(wct);
- mHomeTask = taskInfo;
- }
- mSyncQueue.runInSync(t -> {
- // Reset several properties back to fullscreen (PiP, for example, leaves all these
- // properties in a bad state).
- t.setCrop(leash, null);
- t.setPosition(leash, 0, 0);
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- });
- }
-
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (mLaunchRootTask != null && mLaunchRootTask.taskId == taskInfo.taskId
- && !taskInfo.equals(mLaunchRootTask)) {
- mLaunchRootTask = taskInfo;
- }
-
- if (mHomeTask != null && mHomeTask.taskId == taskInfo.taskId
- && !taskInfo.equals(mHomeTask)) {
- mHomeTask = taskInfo;
- }
-
- super.onTaskInfoChanged(taskInfo);
- }
-
- @VisibleForTesting
- void updateKidsModeState() {
- final boolean enabled = mKidsModeSettingsObserver.isEnabled();
- if (mEnabled == enabled) {
- return;
- }
- mEnabled = enabled;
- if (mEnabled) {
- enable();
- } else {
- disable();
- }
- }
-
- @VisibleForTesting
- void enable() {
- // Needed since many Kids apps aren't optimised to support both orientations and it will be
- // hard for kids to understand the app compat mode.
- // TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
- if (mReverseDefaultRotationEnabled) {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
- /* fromOrientations */
- new int[]{SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
- /* toOrientations */
- new int[]{SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
- SCREEN_ORIENTATION_SENSOR_LANDSCAPE});
- } else {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
- /* fromOrientations */ null, /* toOrientations */ null);
- }
- final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
- if (displayLayout != null) {
- mDisplayWidth = displayLayout.width();
- mDisplayHeight = displayLayout.height();
- }
- mInsetsState.set(mDisplayController.getInsetsState(DEFAULT_DISPLAY));
- mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
- mOnInsetsChangedListener);
- mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
- List<TaskAppearedInfo> taskAppearedInfos = registerOrganizer();
- for (int i = 0; i < taskAppearedInfos.size(); i++) {
- final TaskAppearedInfo info = taskAppearedInfos.get(i);
- onTaskAppeared(info.getTaskInfo(), info.getLeash());
- }
- createRootTask(DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, mCookie);
- updateTask();
- }
-
- @VisibleForTesting
- void disable() {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ false,
- /* fromOrientations */ null, /* toOrientations */ null);
- mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
- mOnInsetsChangedListener);
- mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
- updateTask();
- final WindowContainerToken token = mLaunchRootTask.token;
- if (token != null) {
- deleteRootTask(token);
- }
- mLaunchRootTask = null;
- mLaunchRootLeash = null;
- if (mHomeTask != null && mHomeTask.token != null) {
- final WindowContainerToken homeToken = mHomeTask.token;
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- wct.setBounds(homeToken, null);
- mSyncQueue.queue(wct);
- }
- mHomeTask = null;
- unregisterOrganizer();
- }
-
- private void updateTask() {
- updateTask(getWindowContainerTransaction());
- }
-
- private void updateTask(WindowContainerTransaction wct) {
- if (mLaunchRootTask == null || mLaunchRootLeash == null) {
- return;
- }
- final Rect taskBounds = calculateBounds();
- final WindowContainerToken rootToken = mLaunchRootTask.token;
- wct.setBounds(rootToken, mEnabled ? taskBounds : null);
- wct.setLaunchRoot(rootToken,
- mEnabled ? CONTROLLED_WINDOWING_MODES : null,
- mEnabled ? CONTROLLED_ACTIVITY_TYPES : null);
- wct.reparentTasks(
- mEnabled ? null : rootToken /* currentParent */,
- mEnabled ? rootToken : null /* newParent */,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */);
- wct.reorder(rootToken, mEnabled /* onTop */);
- mSyncQueue.queue(wct);
- if (mEnabled) {
- final SurfaceControl rootLeash = mLaunchRootLeash;
- mSyncQueue.runInSync(t -> {
- t.setPosition(rootLeash, taskBounds.left, taskBounds.top);
- t.setWindowCrop(rootLeash, mDisplayWidth, mDisplayHeight);
- });
- }
- }
-
- private Rect calculateBounds() {
- final Rect bounds = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
- bounds.inset(mInsetsState.calculateInsets(
- bounds, WindowInsets.Type.navigationBars(), false /* ignoreVisibility */));
- return bounds;
- }
-
- private void updateBounds() {
- if (mLaunchRootTask == null) {
- return;
- }
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- final Rect taskBounds = calculateBounds();
- wct.setBounds(mLaunchRootTask.token, taskBounds);
- wct.setBounds(mHomeTask.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
- mSyncQueue.queue(wct);
- final SurfaceControl finalLeash = mLaunchRootLeash;
- mSyncQueue.runInSync(t -> {
- t.setPosition(finalLeash, taskBounds.left, taskBounds.top);
- t.setWindowCrop(finalLeash, mDisplayWidth, mDisplayHeight);
- });
- }
-
- @VisibleForTesting
- WindowContainerTransaction getWindowContainerTransaction() {
- return new WindowContainerTransaction();
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + " mEnabled=" + mEnabled);
- pw.println(innerPrefix + " mLaunchRootTask=" + mLaunchRootTask);
- pw.println(innerPrefix + " mLaunchRootLeash=" + mLaunchRootLeash);
- pw.println(innerPrefix + " mDisplayWidth=" + mDisplayWidth);
- pw.println(innerPrefix + " mDisplayHeight=" + mDisplayHeight);
- pw.println(innerPrefix + " mInsetsState=" + mInsetsState);
- super.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 07d11cf..b14c3c1 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
@@ -447,7 +447,7 @@
}
/**
- * Callback when launcher finishes swipe-pip-to-home operation.
+ * Callback when launcher finishes preparation of swipe-pip-to-home operation.
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
@@ -534,8 +534,7 @@
return;
}
- final Rect displayBounds = mPipBoundsState.getDisplayBounds();
- final Rect destinationBounds = new Rect(displayBounds);
+ final Rect destinationBounds = new Rect(getExitDestinationBounds());
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
@@ -1146,7 +1145,7 @@
public void setPipVisibility(boolean visible) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"setPipVisibility: %s, state=%s visible=%s",
- mTaskInfo.topActivity, mPipTransitionState, visible);
+ (mTaskInfo != null ? mTaskInfo.topActivity : null), mPipTransitionState, visible);
if (!isInPip()) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 86b0f33..b8407c46 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -351,7 +351,7 @@
if (taskInfo != null) {
startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
mPipBoundsState.getBounds(), mPipBoundsState.getBounds(),
- new Rect(mExitDestinationBounds), Surface.ROTATION_0);
+ new Rect(mExitDestinationBounds), Surface.ROTATION_0, null /* startT */);
}
mExitDestinationBounds.setEmpty();
mCurrentPipTaskToken = null;
@@ -604,14 +604,8 @@
}
}
- // Set the initial frame as scaling the end to the start.
final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
destinationBounds.offset(-offset.x, -offset.y);
- startTransaction.setWindowCrop(pipLeash, destinationBounds.width(),
- destinationBounds.height());
- mSurfaceTransactionHelper.scale(startTransaction, pipLeash, destinationBounds,
- currentBounds);
- startTransaction.apply();
// Check if it is fixed rotation.
final int rotationDelta;
@@ -641,7 +635,7 @@
rotationDelta = Surface.ROTATION_0;
}
startExpandAnimation(taskInfo, pipLeash, currentBounds, currentBounds, destinationBounds,
- rotationDelta);
+ rotationDelta, startTransaction);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@@ -697,7 +691,7 @@
private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
final Rect baseBounds, final Rect startBounds, final Rect endBounds,
- final int rotationDelta) {
+ final int rotationDelta, @Nullable SurfaceControl.Transaction startTransaction) {
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, endBounds);
final PipAnimationController.PipTransitionAnimator animator =
@@ -705,9 +699,14 @@
endBounds, sourceHintRect, TRANSITION_DIRECTION_LEAVE_PIP,
0 /* startingAngle */, rotationDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
- .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration);
+ if (startTransaction != null) {
+ animator.setPipTransactionHandler(mTransactionConsumer).applySurfaceControlTransaction(
+ leash, startTransaction, PipAnimationController.FRACTION_START);
+ startTransaction.apply();
+ }
+ animator.setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipOrganizer.getPipTransactionHandler())
- .setDuration(mEnterExitAnimationDuration)
.start();
}
@@ -954,7 +953,8 @@
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
// reparent the PIP activity to a new PIP task (in case there are other activities
- // in the original Task), so we should also reparent the overlay to the PIP task.
+ // in the original Task, in other words multi-activity apps), so we should also reparent
+ // the overlay to the final PIP task.
startTransaction.reparent(swipePipToHomeOverlay, leash)
.setLayer(swipePipToHomeOverlay, Integer.MAX_VALUE);
mPipOrganizer.mSwipePipToHomeOverlay = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index fc674a8..f9332e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -63,6 +63,15 @@
if (pipBoundsState.isImeShowing()) {
insets.bottom -= pipBoundsState.getImeHeight();
}
+ // if PiP is stashed we only adjust the vertical position if it's outside of insets and
+ // ignore all keep clear areas, since it's already on the side
+ if (pipBoundsState.isStashed()) {
+ if (startingBounds.bottom > insets.bottom || startingBounds.top < insets.top) {
+ // bring PiP back to be aligned by bottom inset
+ startingBounds.offset(0, insets.bottom - startingBounds.bottom);
+ }
+ return startingBounds;
+ }
Rect pipBounds = new Rect(startingBounds);
boolean shouldApplyGravity = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 9729a40..da455f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -33,9 +33,10 @@
import androidx.annotation.NonNull;
import com.android.wm.shell.R;
-import com.android.wm.shell.bubbles.DismissView;
-import com.android.wm.shell.common.DismissCircleView;
+import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.bubbles.DismissCircleView;
+import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -106,6 +107,7 @@
}
mTargetViewContainer = new DismissView(mContext);
+ DismissViewUtils.setup(mTargetViewContainer);
mTargetView = mTargetViewContainer.getCircle();
mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index 7f62c62..5d858fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -410,6 +410,7 @@
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mAllowTouches=" + mAllowTouches);
+ pw.println(innerPrefix + "mAllowInputEvents=" + mAllowInputEvents);
pw.println(innerPrefix + "mActivePointerId=" + mActivePointerId);
pw.println(innerPrefix + "mLastTouchDisplayId=" + mLastTouchDisplayId);
pw.println(innerPrefix + "mDownTouch=" + mDownTouch);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a612f5f..843e5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -313,7 +313,7 @@
private Pair<int[], TaskSnapshot[]> getSnapshotsForPausingTasks() {
int[] taskIds = null;
TaskSnapshot[] snapshots = null;
- if (mPausingTasks.size() > 0) {
+ if (mPausingTasks != null && mPausingTasks.size() > 0) {
taskIds = new int[mPausingTasks.size()];
snapshots = new TaskSnapshot[mPausingTasks.size()];
try {
@@ -424,6 +424,7 @@
// the change count). This lets us categorize things into above/below/between
// while maintaining their relative ordering.
final int belowLayers = info.getChanges().size();
+ final int middleLayers = info.getChanges().size() * 2;
final int aboveLayers = info.getChanges().size() * 3;
for (int i = 0; i < info.getChanges().size(); ++i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -441,14 +442,19 @@
belowLayers - i, info, t, mLeashMap);
apps.add(target);
if (TransitionUtil.isClosingType(change.getMode())) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding pausing leaf taskId=%d", taskInfo.taskId);
- // raise closing (pausing) task to "above" layer so it isn't covered
- t.setLayer(target.leash, aboveLayers - i);
mPausingTasks.add(new TaskState(change, target.leash));
if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding pausing leaf home taskId=%d", taskInfo.taskId);
// This can only happen if we have a separate recents/home (3p launcher)
mPausingSeparateHome = true;
+ } else {
+ final int layer = aboveLayers - i;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding pausing leaf taskId=%d at layer=%d",
+ taskInfo.taskId, layer);
+ // raise closing (pausing) task to "above" layer so it isn't covered
+ t.setLayer(target.leash, layer);
}
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
@@ -456,8 +462,12 @@
}
} else if (taskInfo != null
&& taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
- // There's a 3p launcher, so make sure recents goes above that.
- t.setLayer(target.leash, aboveLayers - i);
+ final int layer = middleLayers - i;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " setting recents activity layer=%d", layer);
+ // There's a 3p launcher, so make sure recents goes above that, but under
+ // the pausing apps.
+ t.setLayer(target.leash, layer);
} else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
// do nothing
} else if (TransitionUtil.isOpeningType(change.getMode())) {
@@ -468,16 +478,18 @@
} else if (taskInfo != null && TransitionInfo.isIndependent(change, info)) {
// Root tasks
if (TransitionUtil.isClosingType(change.getMode())) {
+ final int layer = aboveLayers - i;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding pausing taskId=%d", taskInfo.taskId);
+ " adding pausing taskId=%d at layer=%d", taskInfo.taskId, layer);
// raise closing (pausing) task to "above" layer so it isn't covered
- t.setLayer(change.getLeash(), aboveLayers - i);
+ t.setLayer(change.getLeash(), layer);
mPausingTasks.add(new TaskState(change, null /* leash */));
} else if (TransitionUtil.isOpeningType(change.getMode())) {
+ final int layer = belowLayers - i;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding opening taskId=%d", taskInfo.taskId);
+ " adding opening taskId=%d at layer=%d", taskInfo.taskId, layer);
// Put into the "below" layer space.
- t.setLayer(change.getLeash(), belowLayers - i);
+ t.setLayer(change.getLeash(), layer);
mOpeningTasks.add(new TaskState(change, null /* leash */));
}
} else if (TransitionUtil.isDividerBar(change)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index b5d4a9d..acc1c5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -23,7 +23,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -378,6 +377,27 @@
return mMainStage.isActive();
}
+ /** @return whether the transition-request implies entering pip from split. */
+ public boolean requestImpliesSplitToPip(TransitionRequestInfo request) {
+ if (!isSplitActive() || !mMixedHandler.requestHasPipEnter(request)) {
+ return false;
+ }
+
+ if (request.getTriggerTask() != null && getSplitPosition(
+ request.getTriggerTask().taskId) != SPLIT_POSITION_UNDEFINED) {
+ return true;
+ }
+
+ // If one of the splitting tasks support auto-pip, wm-core might reparent the task to TDA
+ // and file a TRANSIT_PIP transition when finishing transitions.
+ // @see com.android.server.wm.RootWindowContainer#moveActivityToPinnedRootTask
+ if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+ return true;
+ }
+
+ return false;
+ }
+
/** Checks if `transition` is a pending enter-split transition. */
public boolean isPendingEnter(IBinder transition) {
return mSplitTransitions.isPendingEnter(transition);
@@ -2357,6 +2377,11 @@
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
}
}
+
+ // When split in the background, it should be only opening/dismissing transition and
+ // would keep out not empty. Prevent intercepting all transitions for split screen when
+ // it is in the background and not identify to handle it.
+ return (!out.isEmpty() || isSplitScreenVisible()) ? out : null;
} else {
if (isOpening && getStageOfTask(triggerTask) != null) {
// One task is appearing into split, prepare to enter split screen.
@@ -2365,8 +2390,8 @@
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
}
+ return out;
}
- return out;
}
/**
@@ -2428,6 +2453,8 @@
mSplitLayout.setFreezeDividerWindow(false);
final StageChangeRecord record = new StageChangeRecord();
+ final int transitType = info.getType();
+ boolean hasEnteringPip = false;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2435,6 +2462,10 @@
mSplitLayout.update(startTransaction);
}
+ if (mMixedHandler.isEnteringPip(change, transitType)) {
+ hasEnteringPip = true;
+ }
+
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo == null) continue;
if (taskInfo.token.equals(mRootTaskInfo.token)) {
@@ -2483,6 +2514,13 @@
}
}
}
+
+ if (hasEnteringPip) {
+ mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
+ startTransaction, finishTransaction, finishCallback);
+ return true;
+ }
+
final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
|| dismissStages.size() == 1) {
@@ -2498,8 +2536,9 @@
&& getStageType(dismissStages.valueAt(0)) == STAGE_TYPE_MAIN)
|| mMainStage.getChildCount() == 0 ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
// If there is a fullscreen opening change, we should not bring stage to top.
- prepareExitSplitScreen(record.mContainShowFullscreenChange
- ? STAGE_TYPE_UNDEFINED : dismissTop, wct);
+ prepareExitSplitScreen(
+ !record.mContainShowFullscreenChange && isSplitScreenVisible()
+ ? dismissTop : STAGE_TYPE_UNDEFINED, wct);
mSplitTransitions.startDismissTransition(wct, this, dismissTop,
EXIT_REASON_APP_FINISHED);
// This can happen in some pathological cases. For example:
@@ -2814,19 +2853,21 @@
}
}
- mRecentTasks.ifPresent(recentTasks -> {
+ if (shouldBreakPairedTaskInRecents(dismissReason)) {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
- if (shouldBreakPairedTaskInRecents(dismissReason)) {
- for (TransitionInfo.Change change : info.getChanges()) {
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null
- && taskInfo.getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW) {
- recentTasks.removeSplitPair(taskInfo.taskId);
- }
+ mRecentTasks.ifPresent(recentTasks -> {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo != null && (getStageOfTask(taskInfo) != null
+ || getSplitItemPosition(change.getLastParent())
+ != SPLIT_POSITION_UNDEFINED)) {
+ recentTasks.removeSplitPair(taskInfo.taskId);
}
- }
- });
+ }
+ });
+ }
mSplitRequest = null;
// Update local states.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index bda25d5..a28ce55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -33,7 +33,6 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.os.IBinder;
-import android.util.Log;
import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -43,10 +42,10 @@
import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
-import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -55,6 +54,7 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.StageCoordinator;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.unfold.UnfoldTransitionHandler;
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
@@ -74,6 +74,7 @@
private final KeyguardTransitionHandler mKeyguardHandler;
private DesktopModeController mDesktopModeController;
private DesktopTasksController mDesktopTasksController;
+ private UnfoldTransitionHandler mUnfoldHandler;
private static class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -93,6 +94,9 @@
/** Recents Transition while in desktop mode. */
static final int TYPE_RECENTS_DURING_DESKTOP = 6;
+ /** Fuld/Unfold transition. */
+ static final int TYPE_UNFOLD = 7;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -146,7 +150,8 @@
Optional<RecentsTransitionHandler> recentsHandlerOptional,
KeyguardTransitionHandler keyguardHandler,
Optional<DesktopModeController> desktopModeControllerOptional,
- Optional<DesktopTasksController> desktopTasksControllerOptional) {
+ Optional<DesktopTasksController> desktopTasksControllerOptional,
+ Optional<UnfoldTransitionHandler> unfoldHandler) {
mPlayer = player;
mKeyguardHandler = keyguardHandler;
if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
@@ -165,6 +170,7 @@
}
mDesktopModeController = desktopModeControllerOptional.orElse(null);
mDesktopTasksController = desktopTasksControllerOptional.orElse(null);
+ mUnfoldHandler = unfoldHandler.orElse(null);
}, this);
}
}
@@ -173,9 +179,7 @@
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()
- && request.getTriggerTask() != null && mSplitHandler.getSplitItemPosition(
- request.getTriggerTask().token) != SPLIT_POSITION_UNDEFINED) {
+ if (mSplitHandler.requestImpliesSplitToPip(request)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
+ "Split-Screen is active, so treat it as Mixed.");
if (request.getRemoteTransition() != null) {
@@ -230,6 +234,16 @@
mixed.mLeftoversHandler = handler.first;
mActiveTransitions.add(mixed);
return handler.second;
+ } else if (mUnfoldHandler != null && mUnfoldHandler.hasUnfold(request)) {
+ final WindowContainerTransaction wct =
+ mUnfoldHandler.handleRequest(transition, request);
+ if (wct != null) {
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_UNFOLD, transition);
+ mixed.mLeftoversHandler = mUnfoldHandler;
+ mActiveTransitions.add(mixed);
+ }
+ return wct;
}
return null;
}
@@ -327,6 +341,19 @@
return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction,
finishTransaction, finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ // Pip auto-entering info might be appended to recent transition like pressing
+ // home-key in 3-button navigation. This offers split handler the opportunity to
+ // handle split to pip animation.
+ if (mPipHandler.isEnteringPip(change, info.getType())
+ && mSplitHandler.getSplitItemPosition(change.getLastParent())
+ != SPLIT_POSITION_UNDEFINED) {
+ return animateEnterPipFromSplit(mixed, info, startTransaction,
+ finishTransaction, finishCallback);
+ }
+ }
+
return animateRecentsDuringSplit(mixed, info, startTransaction, finishTransaction,
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
@@ -335,6 +362,8 @@
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ return animateUnfold(mixed, info, startTransaction, finishTransaction, finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -441,7 +470,8 @@
}
finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
};
- if (isGoingHome) {
+ if (isGoingHome || mSplitHandler.getSplitItemPosition(pipChange.getLastParent())
+ != SPLIT_POSITION_UNDEFINED) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
+ "since entering-PiP caused us to leave split and return home.");
// We need to split the transition into 2 parts: the pip part (animated by pip)
@@ -510,10 +540,27 @@
}
/**
+ * This is intended to be called by SplitCoordinator as a helper to mix a split handling
+ * transition with an entering-pip change. The use-case for this is when an auto-pip change
+ * gets collected into the transition which has already claimed by
+ * StageCoordinator.handleRequest. This happens when launching a fullscreen app while having an
+ * auto-pip activity in the foreground split pair.
+ */
+ // TODO(b/287704263): Remove when split/mixed are reversed.
+ public boolean animatePendingEnterPipFromSplit(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ Transitions.TransitionFinishCallback finishCallback) {
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition);
+ mActiveTransitions.add(mixed);
+ return animateEnterPipFromSplit(mixed, info, startT, finishT, finishCallback);
+ }
+
+ /**
* This is intended to be called by SplitCoordinator as a helper to mix an already-pending
* split transition with a display-change. The use-case for this is when a display
* change/rotation gets collected into a split-screen enter/exit transition which has already
- * been claimed by StageCoordinator.handleRequest . This happens during launcher tests.
+ * been claimed by StageCoordinator.handleRequest. This happens during launcher tests.
*/
public boolean animatePendingSplitWithDisplayChange(@NonNull IBinder transition,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT,
@@ -602,18 +649,15 @@
finishCallback.onTransitionFinished(wct, wctCB);
}
};
- if (!mKeyguardHandler.startAnimation(
- mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
- return false;
- }
mixed.mInFlightSubAnimations++;
// Sync pip state.
if (mPipHandler != null) {
- // We don't know when to apply `startTransaction` so use a separate transaction here.
- // This should be fine because these surface properties are independent.
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- mPipHandler.syncPipSurfaceState(info, t, finishTransaction);
- t.apply();
+ mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
+ }
+ if (!mKeyguardHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
+ mixed.mInFlightSubAnimations--;
+ return false;
}
return true;
}
@@ -642,6 +686,26 @@
return false;
}
+ private boolean animateUnfold(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ mixed.mInFlightSubAnimations--;
+ if (mixed.mInFlightSubAnimations > 0) return;
+ mActiveTransitions.remove(mixed);
+ finishCallback.onTransitionFinished(wct, wctCB);
+ };
+ mixed.mInFlightSubAnimations = 1;
+ // Sync pip state.
+ if (mPipHandler != null) {
+ mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
+ }
+ return mUnfoldHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
+ }
+
/** Use to when split use intent to enter, check if this enter transition should be mixed or
* not.*/
public boolean shouldSplitEnterMixed(PendingIntent intent) {
@@ -653,6 +717,18 @@
return false;
}
+ /** @return whether the transition-request represents a pip-entry. */
+ public boolean requestHasPipEnter(TransitionRequestInfo request) {
+ return mPipHandler.requestHasPipEnter(request);
+ }
+
+ /** Whether a particular change is a window that is entering pip. */
+ // TODO(b/287704263): Remove when split/mixed are reversed.
+ public boolean isEnteringPip(TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ return mPipHandler.isEnteringPip(change, transitType);
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -699,6 +775,8 @@
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
} else {
throw new IllegalStateException("Playing a mixed transition with unknown type? "
+ mixed.mType);
@@ -726,6 +804,8 @@
mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index c504f57..f148412 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -20,6 +20,7 @@
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
+import android.app.ActivityManager;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -178,18 +179,36 @@
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@NonNull TransitionFinishCallback finishCallback) {
if (info.getType() == TRANSIT_CHANGE) {
+ // TODO (b/286928742) unfold transition handler should be part of mixed handler to
+ // handle merges better.
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo != null
+ && taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) {
+ // Tasks that are always on top (e.g. bubbles), will handle their own transition
+ // as they are on top of everything else. So skip merging transitions here.
+ return;
+ }
+ }
// Apply changes happening during the unfold animation immediately
t.apply();
finishCallback.onTransitionFinished(null, null);
}
}
+ /** Whether `request` contains an unfold action. */
+ public boolean hasUnfold(@NonNull TransitionRequestInfo request) {
+ return (request.getType() == TRANSIT_CHANGE
+ && request.getDisplayChange() != null
+ && request.getDisplayChange().isPhysicalDisplayChanged());
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null
- && request.getDisplayChange().isPhysicalDisplayChanged()) {
+ if (hasUnfold(request)) {
mTransition = transition;
return new WindowContainerTransaction();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index c93a11d..331835c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -814,6 +815,7 @@
return false;
}
return DesktopModeStatus.isProto2Enabled()
+ && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
&& taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
&& mDisplayController.getDisplayContext(taskInfo.displayId)
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index e3cb8af..bc89385 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -23,7 +23,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -39,6 +38,7 @@
import android.view.ViewConfiguration;
import android.window.WindowContainerTransaction;
+import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -182,11 +182,8 @@
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[]{android.R.attr.dialogCornerRadius});
- mRelayoutParams.mCornerRadius = ta.getDimensionPixelSize(0, 0);
- ta.recycle();
-
+ mRelayoutParams.mCornerRadius =
+ (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext);
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 68b63e6..e5fc66a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -56,7 +56,6 @@
*/
class DragResizeInputListener implements AutoCloseable {
private static final String TAG = "DragResizeInputListener";
- private static final float TOP_CORNER_PADDING = 1.5f;
private final IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession();
private final Handler mHandler;
private final Choreographer mChoreographer;
@@ -130,12 +129,7 @@
}
/**
- * Updates geometry of this drag resize handler. Needs to be called every time there is a size
- * change to notify the input event receiver it's ready to take the next input event. Otherwise
- * it'll keep batching move events and the drag resize process is stalled.
- *
- * This is also used to update the touch regions of this handler every event dispatched here is
- * a potential resize request.
+ * Updates the geometry (the touch region) of this drag resize handler.
*
* @param taskWidth The width of the task.
* @param taskHeight The height of the task.
@@ -440,10 +434,7 @@
}
double distanceFromCenter = Math.hypot(x - centerX, y - centerY);
- // TODO(b/286461778): Remove this when input in top corner gap no longer goes to header
- float cornerPadding = (ctrlType & CTRL_TYPE_TOP) != 0 ? TOP_CORNER_PADDING : 1;
-
- if (distanceFromCenter < mTaskCornerRadius + mResizeHandleThickness * cornerPadding
+ if (distanceFromCenter < mTaskCornerRadius + mResizeHandleThickness
&& distanceFromCenter >= mTaskCornerRadius) {
return ctrlType;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 4407f2e..ddc7fef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -237,7 +237,12 @@
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = taskBounds.width();
+
+ // We use mDecorationContainerSurface to define input window for task resizing; by layering
+ // it in front of mCaptionContainerSurface, we can allow it to handle input prior to
+ // caption view itself, treating corner inputs as resize events rather than repositioning.
startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
+ .setLayer(mCaptionContainerSurface, -1)
.show(mCaptionContainerSurface);
if (ViewRootImpl.CAPTION_ON_SHELL) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
index e06e074..0f3e0f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -19,14 +19,14 @@
import android.app.Instrumentation
import android.tools.device.flicker.junit.FlickerBuilderProvider
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
abstract class BaseBenchmarkTest
@JvmOverloads
constructor(
- protected open val flicker: FlickerTest,
+ protected open val flicker: LegacyFlickerTest,
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index c98c5a0..d2fe9fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -18,7 +18,7 @@
import android.app.Instrumentation
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
@@ -30,7 +30,7 @@
abstract class BaseTest
@JvmOverloads
constructor(
- override val flicker: FlickerTest,
+ override val flicker: LegacyFlickerTest,
instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
tapl: LauncherInstrumentation = LauncherInstrumentation()
) : BaseBenchmarkTest(flicker, instrumentation, tapl), ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 798cc95..9cc03a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -23,18 +23,18 @@
import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
import android.tools.common.flicker.subject.layers.LayersTraceSubject
import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.WindowUtils
-fun FlickerTest.appPairsDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsDividerIsInvisibleAtEnd() {
+fun LegacyFlickerTest.appPairsDividerIsInvisibleAtEnd() {
assertLayersEnd { this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsDividerBecomesVisible() {
+fun LegacyFlickerTest.appPairsDividerBecomesVisible() {
assertLayers {
this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -42,7 +42,7 @@
}
}
-fun FlickerTest.splitScreenEntered(
+fun LegacyFlickerTest.splitScreenEntered(
component1: IComponentMatcher,
component2: IComponentMatcher,
fromOtherApp: Boolean,
@@ -69,7 +69,7 @@
splitScreenDividerIsVisibleAtEnd()
}
-fun FlickerTest.splitScreenDismissed(
+fun LegacyFlickerTest.splitScreenDismissed(
component1: IComponentMatcher,
component2: IComponentMatcher,
toHome: Boolean
@@ -87,27 +87,27 @@
splitScreenDividerIsInvisibleAtEnd()
}
-fun FlickerTest.splitScreenDividerIsVisibleAtStart() {
+fun LegacyFlickerTest.splitScreenDividerIsVisibleAtStart() {
assertLayersStart { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.splitScreenDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsInvisibleAtStart() {
+fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtStart() {
assertLayersStart { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerIsInvisibleAtEnd() {
+fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtEnd() {
assertLayersEnd { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
}
-fun FlickerTest.splitScreenDividerBecomesVisible() {
+fun LegacyFlickerTest.splitScreenDividerBecomesVisible() {
layerBecomesVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
}
-fun FlickerTest.splitScreenDividerBecomesInvisible() {
+fun LegacyFlickerTest.splitScreenDividerBecomesInvisible() {
assertLayers {
this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
.then()
@@ -115,23 +115,23 @@
}
}
-fun FlickerTest.layerBecomesVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerBecomesVisible(component: IComponentMatcher) {
assertLayers { this.isInvisible(component).then().isVisible(component) }
}
-fun FlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
assertLayers { this.isVisible(component).then().isInvisible(component) }
}
-fun FlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
assertLayersEnd { this.isVisible(component) }
}
-fun FlickerTest.layerKeepVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.layerKeepVisible(component: IComponentMatcher) {
assertLayers { this.isVisible(component) }
}
-fun FlickerTest.splitAppLayerBoundsBecomesVisible(
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -150,7 +150,7 @@
}
}
-fun FlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
assertLayers {
this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
.then()
@@ -161,7 +161,7 @@
}
}
-fun FlickerTest.splitAppLayerBoundsBecomesInvisible(
+fun LegacyFlickerTest.splitAppLayerBoundsBecomesInvisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -180,7 +180,7 @@
}
}
-fun FlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -195,7 +195,7 @@
}
}
-fun FlickerTest.splitAppLayerBoundsKeepVisible(
+fun LegacyFlickerTest.splitAppLayerBoundsKeepVisible(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -210,7 +210,7 @@
}
}
-fun FlickerTest.splitAppLayerBoundsChanges(
+fun LegacyFlickerTest.splitAppLayerBoundsChanges(
component: IComponentMatcher,
landscapePosLeft: Boolean,
portraitPosTop: Boolean
@@ -304,7 +304,7 @@
}
}
-fun FlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
assertWm {
this.isAppWindowInvisible(component)
.then()
@@ -316,39 +316,39 @@
}
}
-fun FlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
assertWm { this.isAppWindowVisible(component).then().isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
assertWmStart { this.isAppWindowVisible(component) }
}
-fun FlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
assertWmEnd { this.isAppWindowVisible(component) }
}
-fun FlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
assertWmStart { this.isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
assertWmEnd { this.isAppWindowInvisible(component) }
}
-fun FlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
assertWmStart { this.notContains(component) }
}
-fun FlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
+fun LegacyFlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
assertWm { this.isAppWindowVisible(component) }
}
-fun FlickerTest.dockedStackDividerIsVisibleAtEnd() {
+fun LegacyFlickerTest.dockedStackDividerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) }
}
-fun FlickerTest.dockedStackDividerBecomesVisible() {
+fun LegacyFlickerTest.dockedStackDividerBecomesVisible() {
assertLayers {
this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -356,7 +356,7 @@
}
}
-fun FlickerTest.dockedStackDividerBecomesInvisible() {
+fun LegacyFlickerTest.dockedStackDividerBecomesInvisible() {
assertLayers {
this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
@@ -364,11 +364,11 @@
}
}
-fun FlickerTest.dockedStackDividerNotExistsAtEnd() {
+fun LegacyFlickerTest.dockedStackDividerNotExistsAtEnd() {
assertLayersEnd { this.notContains(DOCKED_STACK_DIVIDER_COMPONENT) }
}
-fun FlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
rotation: Rotation,
primaryComponent: IComponentMatcher
) {
@@ -380,7 +380,7 @@
}
}
-fun FlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
rotation: Rotation,
primaryComponent: IComponentMatcher
) {
@@ -392,7 +392,7 @@
}
}
-fun FlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
rotation: Rotation,
secondaryComponent: IComponentMatcher
) {
@@ -404,7 +404,7 @@
}
}
-fun FlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
+fun LegacyFlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
rotation: Rotation,
secondaryComponent: IComponentMatcher
) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
index 02d9a056..7b32901 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/ICommonAssertions.kt
@@ -18,7 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
@@ -32,7 +32,7 @@
import org.junit.Test
interface ICommonAssertions {
- val flicker: FlickerTest
+ val flicker: LegacyFlickerTest
/** Checks that all parts of the screen are covered during the transition */
@Presubmit @Test fun entireScreenCovered() = flicker.entireScreenCovered()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 3000008..0f9579d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -20,20 +20,20 @@
import android.system.helpers.CommandsHelper
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import com.android.server.wm.flicker.helpers.setRotation
+import android.tools.device.flicker.legacy.FlickerTestData
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import android.tools.device.flicker.legacy.IFlickerTestData
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.appWindowKeepVisible
import com.android.wm.shell.flicker.layerKeepVisible
import org.junit.After
import org.junit.Assume
import org.junit.Before
-abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val letterboxApp = LetterboxAppHelper(instrumentation)
lateinit var cmdHelper: CommandsHelper
@@ -47,9 +47,7 @@
letterboxApp.launchViaIntent(wmHelper)
setEndRotation()
}
- teardown {
- letterboxApp.exit(wmHelper)
- }
+ teardown { letterboxApp.exit(wmHelper) }
}
@Before
@@ -100,9 +98,9 @@
return res != null && res.contains("true")
}
- fun IFlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
+ fun FlickerTestData.setStartRotation() = setRotation(flicker.scenario.startRotation)
- fun IFlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
+ fun FlickerTestData.setEndRotation() = setRotation(flicker.scenario.endRotation)
/** Checks that app entering letterboxed state have rounded corners */
fun assertLetterboxAppAtStartHasRoundedCorners() {
@@ -131,13 +129,13 @@
}
fun assertAppLetterboxedAtEnd() =
- flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+ flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertAppLetterboxedAtStart() =
- flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+ flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertAppStaysLetterboxed() =
- flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) }
+ flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index 3d83455..a7bd258 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -17,11 +17,12 @@
package com.android.wm.shell.flicker.appcompat
import android.platform.test.annotations.Postsubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,7 +47,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+class OpenAppInSizeCompatModeTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -71,9 +72,7 @@
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
- @Postsubmit
- @Test
- fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+ @Postsubmit @Test fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
/**
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
@@ -96,13 +95,13 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ return LegacyFlickerTestFactory.rotationTests()
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
index c3355ed..e875aae 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -18,29 +18,29 @@
import android.platform.test.annotations.Postsubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-
import androidx.test.filters.RequiresDevice
import org.junit.Test
-
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
* Test launching a fixed portrait letterboxed app in landscape and repositioning to the right.
*
- * To run this test: `atest WMShellFlickerTests:RepositionFixedPortraitAppTest`
- * Actions:
+ * To run this test: `atest WMShellFlickerTests:RepositionFixedPortraitAppTest` Actions:
+ *
* ```
* Launch a fixed portrait app in landscape to letterbox app
* Double tap to the right to reposition app and wait for app to move
* ```
*
- * Notes:
+ * Notes:
+ *
* ```
* Some default assertions (e.g., nav bar, status bar and screen covered)
* are inherited [BaseTest]
@@ -49,7 +49,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class RepositionFixedPortraitAppTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+class RepositionFixedPortraitAppTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation).bounds
/** {@inheritDoc} */
@@ -73,31 +73,25 @@
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
- @Postsubmit
- @Test
- fun letterboxAppLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+ @Postsubmit @Test fun letterboxAppLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
- @Postsubmit
- @Test
- fun appStaysLetterboxed() = assertAppStaysLetterboxed()
+ @Postsubmit @Test fun appStaysLetterboxed() = assertAppStaysLetterboxed()
- @Postsubmit
- @Test
- fun appKeepVisible() = assertLetterboxAppKeepVisible()
+ @Postsubmit @Test fun appKeepVisible() = assertLetterboxAppKeepVisible()
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_90)
)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index c2057d2..a18a144 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -17,10 +17,11 @@
package com.android.wm.shell.flicker.appcompat
import android.platform.test.annotations.Postsubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import org.junit.Test
@@ -47,7 +48,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+class RestartAppInSizeCompatModeTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -70,13 +71,9 @@
}
}
- @Postsubmit
- @Test
- fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+ @Postsubmit @Test fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
- @Postsubmit
- @Test
- fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+ @Postsubmit @Test fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
@Postsubmit
@Test
@@ -94,13 +91,13 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ return LegacyFlickerTestFactory.rotationTests()
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index bab81d7..d38bcc2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -23,9 +23,9 @@
import android.os.ServiceManager
import android.tools.common.Rotation
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
-import android.tools.device.flicker.legacy.IFlickerTestData
+import android.tools.device.flicker.legacy.FlickerTestData
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.SYSTEMUI_PACKAGE
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiObject2
@@ -35,7 +35,7 @@
import org.junit.runners.Parameterized
/** Base configurations for Bubble flicker tests */
-abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class BaseBubbleScreen(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val testApp = LaunchBubbleHelper(instrumentation)
@@ -79,19 +79,18 @@
}
}
- protected fun IFlickerTestData.waitAndGetAddBubbleBtn(): UiObject2? =
+ protected fun FlickerTestData.waitAndGetAddBubbleBtn(): UiObject2? =
device.wait(Until.findObject(By.text("Add Bubble")), FIND_OBJECT_TIMEOUT)
- protected fun IFlickerTestData.waitAndGetCancelAllBtn(): UiObject2? =
+ protected fun FlickerTestData.waitAndGetCancelAllBtn(): UiObject2? =
device.wait(Until.findObject(By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT)
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
const val FIND_OBJECT_TIMEOUT = 2000L
const val SYSTEM_UI_PACKAGE = SYSTEMUI_PACKAGE
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index 2474ecf..bc565bc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -21,7 +21,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiObject2
@@ -44,7 +44,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FlakyTest(bugId = 217777115)
-open class ChangeActiveActivityFromBubbleTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+open class ChangeActiveActivityFromBubbleTest(flicker: LegacyFlickerTest) :
+ BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
index bdfdad5..abc6b9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
@@ -17,11 +17,11 @@
package com.android.wm.shell.flicker.bubble
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class ChangeActiveActivityFromBubbleTestCfArm(flicker: FlickerTest) :
+open class ChangeActiveActivityFromBubbleTestCfArm(flicker: LegacyFlickerTest) :
ChangeActiveActivityFromBubbleTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 8474ce0..d02ee4b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -21,7 +21,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.test.filters.RequiresDevice
@@ -44,7 +44,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class DragToDismissBubbleScreenTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+open class DragToDismissBubbleScreenTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val displaySize = DisplayMetrics()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
index 62fa7b4..ee55eca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
@@ -17,11 +17,11 @@
package com.android.wm.shell.flicker.bubble
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class DragToDismissBubbleScreenTestCfArm(flicker: FlickerTest) :
+class DragToDismissBubbleScreenTestCfArm(flicker: LegacyFlickerTest) :
DragToDismissBubbleScreenTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index 889e177..c430feb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -21,7 +21,7 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.view.WindowInsets
import android.view.WindowManager
import androidx.test.filters.RequiresDevice
@@ -48,7 +48,8 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenActivityFromBubbleOnLocksreenTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+class OpenActivityFromBubbleOnLocksreenTest(flicker: LegacyFlickerTest) :
+ BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index 07ba4133..5085394 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
@@ -42,7 +42,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class OpenActivityFromBubbleTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+open class OpenActivityFromBubbleTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
index 6c61710..6a46d23 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
@@ -17,10 +17,11 @@
package com.android.wm.shell.flicker.bubble
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenActivityFromBubbleTestCfArm(flicker: FlickerTest) : OpenActivityFromBubbleTest(flicker)
+class OpenActivityFromBubbleTestCfArm(flicker: LegacyFlickerTest) :
+ OpenActivityFromBubbleTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 29f76d0..43722ae 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
@@ -41,7 +41,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTest(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
+open class SendBubbleNotificationTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
index e323ebf..a401cb4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
@@ -17,11 +17,11 @@
package com.android.wm.shell.flicker.bubble
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTestCfArm(flicker: FlickerTest) :
+open class SendBubbleNotificationTestCfArm(flicker: LegacyFlickerTest) :
SendBubbleNotificationTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
index f7ce870..36bbafb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
@@ -24,8 +24,8 @@
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.RequiresDevice
@@ -69,17 +69,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
- AutoEnterPipOnGoToHomeTest(flicker) {
+class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
+ AutoEnterPipOnGoToHomeTest(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
/** Second app used to enter split screen mode */
protected val secondAppForSplitScreen = getSplitScreenApp(instrumentation)
fun getSplitScreenApp(instrumentation: Instrumentation): StandardAppHelper =
- SimpleAppHelper(
- instrumentation,
- ActivityOptions.SplitScreen.Primary.LABEL,
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
- )
+ SimpleAppHelper(
+ instrumentation,
+ ActivityOptions.SplitScreen.Primary.LABEL,
+ ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
+ )
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -91,11 +91,11 @@
enterSplitScreen()
// wait until split screen is established
wmHelper
- .StateSyncBuilder()
- .withWindowSurfaceAppeared(pipApp)
- .withWindowSurfaceAppeared(secondAppForSplitScreen)
- .withSplitDividerVisible()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withWindowSurfaceAppeared(pipApp)
+ .withWindowSurfaceAppeared(secondAppForSplitScreen)
+ .withSplitDividerVisible()
+ .waitForAndVerify()
pipApp.enableAutoEnterForPipActivity()
}
teardown {
@@ -120,8 +120,8 @@
// contains more than 3 task views. We need to use uiautomator directly to find the
// second task to split.
tapl.workspace.switchToOverview().overviewActions.clickSplit()
- val snapshots = tapl.device.wait(Until.findObjects(overviewSnapshotSelector),
- TIMEOUT_MS)
+ val snapshots =
+ tapl.device.wait(Until.findObjects(overviewSnapshotSelector), TIMEOUT_MS)
if (snapshots == null || snapshots.size < 1) {
error("Fail to find a overview snapshot to split.")
}
@@ -137,12 +137,12 @@
snapshots[0].click()
} else {
tapl.workspace
- .switchToOverview()
- .currentTask
- .tapMenu()
- .tapSplitMenuItem()
- .currentTask
- .open()
+ .switchToOverview()
+ .currentTask
+ .tapMenu()
+ .tapSplitMenuItem()
+ .currentTask
+ .open()
}
SystemClock.sleep(TIMEOUT_MS)
}
@@ -190,11 +190,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index b95732e..2f7a25e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -53,10 +53,9 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit = {
- transitions { tapl.goHome() }
- }
+open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
+ EnterPipViaAppUiButtonTest(flicker) {
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index afcc172..68bc9a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -20,7 +20,7 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -53,7 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipBySwipingDownTest(flicker: FlickerTest) : ClosePipTransition(flicker) {
+open class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions {
val pipRegion = wmHelper.getWindowRegion(pipApp).bounds
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
index 02f6010..7a66889 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,20 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ClosePipBySwipingDownTestCfArm(flicker: FlickerTest) : ClosePipBySwipingDownTest(flicker) {
+class ClosePipBySwipingDownTestCfArm(flicker: LegacyFlickerTest) :
+ ClosePipBySwipingDownTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
index e52b71e..a17144b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
@@ -20,14 +20,14 @@
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for exiting pip (closing pip window) without returning to the app */
-abstract class ClosePipTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class ClosePipTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup { this.setRotation(flicker.scenario.startRotation) }
teardown { this.setRotation(Rotation.ROTATION_0) }
@@ -74,15 +74,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 86fe583..dc48696 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -53,7 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTest(flicker: FlickerTest) : ClosePipTransition(flicker) {
+open class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.closePipWindow(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
index 05262fe..718b14b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,21 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTestCfArm(flicker: FlickerTest) :
+open class ClosePipWithDismissButtonTestCfArm(flicker: LegacyFlickerTest) :
ClosePipWithDismissButtonTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 01d67cc..5e39262 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -44,10 +44,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipOnUserLeaveHintTest(flicker: FlickerTest) : EnterPipTransition(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit = {
- transitions { tapl.goHome() }
- }
+open class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
index 90f99c0..2b3e76a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.wm.shell.flicker.pip
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,4 +27,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipOnUserLeaveHintTestCfArm(flicker: FlickerTest) : EnterPipOnUserLeaveHintTest(flicker)
+class EnterPipOnUserLeaveHintTestCfArm(flicker: LegacyFlickerTest) :
+ EnterPipOnUserLeaveHintTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 5480144..ec35837 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -21,11 +21,12 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.entireScreenCovered
@@ -68,15 +69,13 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientation(flicker: FlickerTest) : PipTransition(flicker) {
+open class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = FixedOrientationAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
override val thisTransition: FlickerBuilder.() -> Unit = {
- teardown {
- testApp.exit(wmHelper)
- }
+ teardown { testApp.exit(wmHelper) }
transitions {
// Enter PiP, and assert that the PiP is within bounds now that the device is back
// in portrait
@@ -95,14 +94,13 @@
setup {
// Launch a portrait only app on the fullscreen stack
testApp.launchViaIntent(
- wmHelper,
- stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())
)
// Launch the PiP activity fixed as landscape, but don't enter PiP
pipApp.launchViaIntent(
- wmHelper,
- stringExtras =
- mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
)
}
}
@@ -207,13 +205,13 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
index 5841666..9264219 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
@@ -17,9 +17,10 @@
package com.android.wm.shell.flicker.pip
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,19 +30,19 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientationCfArm(flicker: FlickerTest) :
+open class EnterPipToOtherOrientationCfArm(flicker: LegacyFlickerTest) :
EnterPipToOtherOrientation(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
index cdbdb85..6d20740 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
@@ -20,16 +20,14 @@
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.Test
import org.junit.runners.Parameterized
-abstract class EnterPipTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class EnterPipTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
- setup {
- pipApp.launchViaIntent(wmHelper)
- }
+ setup { pipApp.launchViaIntent(wmHelper) }
}
/** Checks [pipApp] window remains visible throughout the animation */
@@ -126,15 +124,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index 95725b6..76c811c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -18,7 +18,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -50,7 +50,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipViaAppUiButtonTest(flicker: FlickerTest) : EnterPipTransition(flicker) {
+open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.clickEnterPipButton(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
index 4390f0b..78e8049 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,20 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipViaAppUiButtonTestCfArm(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
+class EnterPipViaAppUiButtonTestCfArm(flicker: LegacyFlickerTest) :
+ EnterPipViaAppUiButtonTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
index 5ac9829..dfffba8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -19,14 +19,14 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for pip expand tests */
-abstract class ExitPipToAppTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class ExitPipToAppTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
protected val testApp = SimpleAppHelper(instrumentation)
/**
@@ -130,15 +130,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 0b3d16a..b80b748 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -18,7 +18,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -52,7 +52,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaExpandButtonTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
+open class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
+ ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
// launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
index eccb85d..e25c0d6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,21 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaExpandButtonTestCfArm(flicker: FlickerTest) :
+class ExitPipToAppViaExpandButtonTestCfArm(flicker: LegacyFlickerTest) :
ExitPipToAppViaExpandButtonTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index bb2d40b..f003ed8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -18,7 +18,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -51,7 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaIntentTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
+open class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
// launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
index 6ab6a1f..be19f3c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,20 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaIntentTestCfArm(flicker: FlickerTest) : ExitPipToAppViaIntentTest(flicker) {
+class ExitPipToAppViaIntentTestCfArm(flicker: LegacyFlickerTest) :
+ ExitPipToAppViaIntentTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index fd16b6e..a1d3a11 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -55,7 +55,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnDoubleClickTest(flicker: FlickerTest) : PipTransition(flicker) {
+open class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.doubleClickPipWindow(wmHelper) }
}
@@ -142,15 +142,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
index c096234..3095cac 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,21 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnDoubleClickTestTestCfArm(flicker: FlickerTest) :
+class ExpandPipOnDoubleClickTestTestCfArm(flicker: LegacyFlickerTest) :
ExpandPipOnDoubleClickTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 253aa4c..8c8d280 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -20,8 +20,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -34,7 +34,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnPinchOpenTest(flicker: FlickerTest) : PipTransition(flicker) {
+open class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) }
}
@@ -55,15 +55,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
index e064bf2..1a1ce68 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,20 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnPinchOpenTestCfArm(flicker: FlickerTest) : ExpandPipOnPinchOpenTest(flicker) {
+class ExpandPipOnPinchOpenTestCfArm(flicker: LegacyFlickerTest) :
+ ExpandPipOnPinchOpenTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 094060f..4f88184 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.Direction
import org.junit.FixMethodOrder
@@ -55,7 +55,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipDownOnShelfHeightChange(flicker: FlickerTest) : MovePipShelfHeightTransition(flicker) {
+class MovePipDownOnShelfHeightChange(flicker: LegacyFlickerTest) :
+ MovePipShelfHeightTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
teardown { testApp.exit(wmHelper) }
transitions { testApp.launchViaIntent(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index ff51c27..dffc822 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -18,11 +18,12 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -38,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipOnImeVisibilityChangeTest(flicker: FlickerTest) : PipTransition(flicker) {
+open class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val imeApp = ImeAppHelper(instrumentation)
override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -80,7 +81,7 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
index d3d77d2..63292a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
@@ -17,9 +17,10 @@
package com.android.wm.shell.flicker.pip
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,7 +29,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipOnImeVisibilityChangeTestCfArm(flicker: FlickerTest) :
+class MovePipOnImeVisibilityChangeTestCfArm(flicker: LegacyFlickerTest) :
MovePipOnImeVisibilityChangeTest(flicker) {
companion object {
private const val TAG_IME_VISIBLE = "imeIsVisible"
@@ -36,7 +37,7 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
index 109354a..9a2fa09 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -19,15 +19,15 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.wm.shell.flicker.Direction
import org.junit.Test
import org.junit.runners.Parameterized
/** Base class for pip tests with Launcher shelf height change */
-abstract class MovePipShelfHeightTransition(flicker: FlickerTest) : PipTransition(flicker) {
+abstract class MovePipShelfHeightTransition(flicker: LegacyFlickerTest) : PipTransition(flicker) {
protected val testApp = FixedOrientationAppHelper(instrumentation)
/** Checks [pipApp] window remains visible throughout the animation */
@@ -111,15 +111,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 27b061b..afb4af6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.Direction
import org.junit.FixMethodOrder
@@ -55,14 +55,13 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipUpOnShelfHeightChangeTest(flicker: FlickerTest) :
+open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) :
MovePipShelfHeightTransition(flicker) {
- override val thisTransition: FlickerBuilder.() -> Unit =
- {
- setup { testApp.launchViaIntent(wmHelper) }
- transitions { tapl.pressHome() }
- teardown { testApp.exit(wmHelper) }
- }
+ override val thisTransition: FlickerBuilder.() -> Unit = {
+ setup { testApp.launchViaIntent(wmHelper) }
+ transitions { tapl.pressHome() }
+ teardown { testApp.exit(wmHelper) }
+ }
/** Checks that the visible region of [pipApp] window always moves up during the animation. */
@Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index 9f81ba8..7085d55 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -20,8 +20,8 @@
import android.platform.test.annotations.RequiresDevice
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
@@ -34,7 +34,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipDragTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private var isDraggedLeft: Boolean = true
override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -81,13 +81,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 9fe9f52..2b87766 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
@@ -38,7 +38,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
// represents the direction in which the pip window should be snapping
private var willSnapRight: Boolean = true
@@ -99,15 +99,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 60bf5ff..adc5ee3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -36,7 +36,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 270677470)
-class PipPinchInTest(flicker: FlickerTest) : PipTransition(flicker) {
+class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
}
@@ -57,15 +57,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 17a178f..096af39 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -22,7 +22,7 @@
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import android.tools.device.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.PipAppHelper
@@ -32,7 +32,7 @@
import com.google.common.truth.Truth
import org.junit.Test
-abstract class PipTransition(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected val pipApp = PipAppHelper(instrumentation)
protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
@@ -78,16 +78,16 @@
/** Defines the default method of entering PiP */
protected open val defaultEnterPip: FlickerBuilder.() -> Unit = {
setup {
- pipApp.launchViaIntentAndWaitForPip(wmHelper,
- stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true"))
+ pipApp.launchViaIntentAndWaitForPip(
+ wmHelper,
+ stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")
+ )
}
}
/** Defines the default teardown required to clean up after the test */
protected open val defaultTeardown: FlickerBuilder.() -> Unit = {
- teardown {
- pipApp.exit(wmHelper)
- }
+ teardown { pipApp.exit(wmHelper) }
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index c618e5a..c315e74 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -21,10 +21,11 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -46,7 +47,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SetRequestedOrientationWhilePinned(flicker: FlickerTest) : PipTransition(flicker) {
+open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
@@ -69,20 +70,19 @@
setup {
// Launch the PiP activity fixed as landscape.
pipApp.launchViaIntent(
- wmHelper,
- stringExtras =
- mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
+ wmHelper,
+ stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
)
// Enter PiP.
broadcastActionTrigger.doAction(ActivityOptions.Pip.ACTION_ENTER_PIP)
// System bar may fade out during fixed rotation.
wmHelper
- .StateSyncBuilder()
- .withPipShown()
- .withRotation(Rotation.ROTATION_0)
- .withNavOrTaskBarVisible()
- .withStatusBarVisible()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withPipShown()
+ .withRotation(Rotation.ROTATION_0)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
}
}
@@ -150,7 +150,7 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ return LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 43d6c8f..0ff9cff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,10 +17,11 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -58,7 +59,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowPipAndRotateDisplay(flicker: FlickerTest) : PipTransition(flicker) {
+open class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
private val screenBoundsEnd = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
@@ -154,13 +155,13 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ return LegacyFlickerTestFactory.rotationTests()
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
index b7a2c47..2516471 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
@@ -16,9 +16,10 @@
package com.android.wm.shell.flicker.pip
+import android.tools.common.flicker.assertions.FlickerTest
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,18 +28,18 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowPipAndRotateDisplayCfArm(flicker: FlickerTest) : ShowPipAndRotateDisplay(flicker) {
+class ShowPipAndRotateDisplayCfArm(flicker: LegacyFlickerTest) : ShowPipAndRotateDisplay(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
- * and navigation modes.
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
+ * orientation and navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ return LegacyFlickerTestFactory.rotationTests()
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 72f25f3..a43ad9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -17,15 +17,14 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.EdgeExtensionComponentMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -46,13 +45,13 @@
/**
* Test copy content from the left to the right side of the split-screen.
*
- * To run this test: `atest WMShellFlickerTests:CopyContentInSplit`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:CopyContentInSplit`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CopyContentInSplit(override val flicker: FlickerTest) :
+class CopyContentInSplit(override val flicker: LegacyFlickerTest) :
CopyContentInSplitBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -62,7 +61,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
override fun cujCompleted() {
@@ -138,8 +136,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 4505b99..0b8f109 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -21,7 +21,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
@@ -41,13 +41,13 @@
/**
* Test dismiss split screen by dragging the divider bar.
*
- * To run this test: `atest WMShellFlickerTests:DismissSplitScreenByDivider`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DismissSplitScreenByDivider`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByDivider(override val flicker: FlickerTest) :
+class DismissSplitScreenByDivider(override val flicker: LegacyFlickerTest) :
DismissSplitScreenByDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index e05b221..38d4b40 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -20,8 +20,8 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesInvisible
@@ -38,13 +38,13 @@
/**
* Test dismiss split screen by go home.
*
- * To run this test: `atest WMShellFlickerTests:DismissSplitScreenByGoHome`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DismissSplitScreenByGoHome`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByGoHome(override val flicker: FlickerTest) :
+class DismissSplitScreenByGoHome(override val flicker: LegacyFlickerTest) :
DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -154,8 +154,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index ed3df9c..a118c08 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -17,13 +17,12 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -44,13 +43,13 @@
/**
* Test resize split by dragging the divider bar.
*
- * To run this test: `atest WMShellFlickerTests:DragDividerToResize`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:DragDividerToResize`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DragDividerToResize(override val flicker: FlickerTest) :
+class DragDividerToResize(override val flicker: LegacyFlickerTest) :
DragDividerToResizeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -60,7 +59,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
override fun cujCompleted() {
@@ -129,8 +127,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index e558686..05c0480 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -22,8 +22,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -45,13 +45,13 @@
* Test enter split screen by dragging app icon from all apps. This test is only for large screen
* devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromAllApps`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromAllApps`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromAllApps(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromAllApps(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromAllAppsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -160,11 +160,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index ab8ecc5..3a75fa6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -22,8 +22,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -44,13 +44,13 @@
* Test enter split screen by dragging app icon from notification. This test is only for large
* screen devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromNotification`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromNotification`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromNotification(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromNotification(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromNotificationBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -162,11 +162,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index 516ca97..6d73f92 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -21,8 +21,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -41,13 +41,13 @@
/**
* Test enter split screen by dragging a shortcut. This test is only for large screen devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromShortcut`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromShortcut`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromShortcut(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromShortcut(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromShortcutBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
@@ -105,11 +105,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 4af7e24..15cae69 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -22,8 +22,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -45,13 +45,13 @@
* Test enter split screen by dragging app icon from taskbar. This test is only for large screen
* devices.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromTaskbar`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenByDragFromTaskbar`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromTaskbar(override val flicker: FlickerTest) :
+class EnterSplitScreenByDragFromTaskbar(override val flicker: LegacyFlickerTest) :
EnterSplitScreenByDragFromTaskbarBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -163,10 +163,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index faad9e8..90399fc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -20,8 +20,8 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -40,13 +40,13 @@
/**
* Test enter split screen from Overview.
*
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenFromOverview`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:EnterSplitScreenFromOverview`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenFromOverview(override val flicker: FlickerTest) :
+class EnterSplitScreenFromOverview(override val flicker: LegacyFlickerTest) :
EnterSplitScreenFromOverviewBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -106,8 +106,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index 195b73a..580b153 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -18,11 +18,11 @@
import android.content.Context
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseBenchmarkTest
-abstract class SplitScreenBase(flicker: FlickerTest) : BaseBenchmarkTest(flicker) {
+abstract class SplitScreenBase(flicker: LegacyFlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
index 1063dfd..27eaa40 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
@@ -39,6 +39,7 @@
import com.android.server.wm.flicker.helpers.NotificationAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary
import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import org.junit.Assert.assertNotNull
@@ -112,6 +113,17 @@
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
+ fun enterSplitViaIntent(
+ wmHelper: WindowManagerStateHelper,
+ primaryApp: StandardAppHelper,
+ secondaryApp: StandardAppHelper
+ ) {
+ val stringExtras = mapOf(Primary.EXTRA_LAUNCH_ADJACENT to "true")
+ primaryApp.launchViaIntent(wmHelper, null, null,
+ stringExtras)
+ waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+
fun splitFromOverview(tapl: LauncherInstrumentation, device: UiDevice) {
// Note: The initial split position in landscape is different between tablet and phone.
// In landscape, tablet will let the first app split to right side, and phone will
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index b4c6afd..e0a47b3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -16,15 +16,14 @@
package com.android.wm.shell.flicker.splitscreen
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -45,13 +44,13 @@
/**
* Test double tap the divider bar to switch the two apps.
*
- * To run this test: `atest WMShellFlickerTests:SwitchAppByDoubleTapDivider`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchAppByDoubleTapDivider`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) :
+class SwitchAppByDoubleTapDivider(override val flicker: LegacyFlickerTest) :
SwitchAppByDoubleTapDividerBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -61,7 +60,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
override fun cujCompleted() {
@@ -122,11 +120,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 078d95d..a406009 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -21,8 +21,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -39,13 +39,13 @@
/**
* Test quick switch to split pair from another app.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromAnotherApp`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromAnotherApp`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromAnotherApp(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromAnotherApp(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromAnotherAppBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 7c84243..251bd10 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -21,8 +21,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -39,13 +39,13 @@
/**
* Test quick switch to split pair from home.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromHome`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromHome`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromHome(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromHome(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromHomeBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index 7c46d3e..1dd45fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -21,8 +21,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.appWindowBecomesVisible
@@ -39,13 +39,13 @@
/**
* Test switch back to split pair from recent.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBackToSplitFromRecent`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBackToSplitFromRecent`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromRecent(override val flicker: FlickerTest) :
+class SwitchBackToSplitFromRecent(override val flicker: LegacyFlickerTest) :
SwitchBackToSplitFromRecentBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -149,11 +149,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index 2cedc35..8f867df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -17,13 +17,12 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -48,13 +47,13 @@
/**
* Test quick switch between two split pairs.
*
- * To run this test: `atest WMShellFlickerTests:SwitchBetweenSplitPairs`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:SwitchBetweenSplitPairs`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairs(override val flicker: FlickerTest) :
+class SwitchBetweenSplitPairs(override val flicker: LegacyFlickerTest) :
SwitchBetweenSplitPairsBenchmark(flicker), ICommonAssertions {
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -64,7 +63,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
override fun cujCompleted() {
@@ -225,8 +223,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 676c150..994d6cb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -21,8 +21,8 @@
import android.tools.common.flicker.subject.region.RegionSubject
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.ICommonAssertions
import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -37,21 +37,21 @@
import org.junit.runners.Parameterized
/**
- * Test unlocking insecure keyguard to back to split screen tasks and verify the transition behavior.
+ * Test unlocking insecure keyguard to back to split screen tasks and verify the transition
+ * behavior.
*
- * To run this test: `atest WMShellFlickerTests:UnlockKeyguardToSplitScreen`
+ * To run this test: `atest WMShellFlickerTestsSplitScreen:UnlockKeyguardToSplitScreen`
*/
@RequiresDevice
@Postsubmit
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class UnlockKeyguardToSplitScreen(override val flicker: FlickerTest) :
- UnlockKeyguardToSplitScreenBenchmark(flicker), ICommonAssertions {
+class UnlockKeyguardToSplitScreen(override val flicker: LegacyFlickerTest) :
+ UnlockKeyguardToSplitScreenBenchmark(flicker), ICommonAssertions {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
- defaultSetup(this)
defaultTeardown(this)
thisTransition(this)
}
@@ -65,33 +65,35 @@
@Test
fun primaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- primaryApp,
- landscapePosLeft = false,
- portraitPosTop = false
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ primaryApp,
+ landscapePosLeft = false,
+ portraitPosTop = false
+ )
@Test
fun secondaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- secondaryApp,
- landscapePosLeft = true,
- portraitPosTop = true
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp,
+ landscapePosLeft = true,
+ portraitPosTop = true
+ )
- @Test
- fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
+ @Test fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
- @Test
- fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
+ @Test fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
@Test
fun notOverlapsForPrimaryAndSecondaryAppLayers() {
flicker.assertLayers {
this.invoke("notOverlapsForPrimaryAndSecondaryLayers") {
- val primaryAppRegions = it.subjects.filter { subject ->
- subject.name.contains(primaryApp.toLayerName()) && subject.isVisible
- }.mapNotNull { primaryApp -> primaryApp.layer.visibleRegion }.toTypedArray()
+ val primaryAppRegions =
+ it.subjects
+ .filter { subject ->
+ subject.name.contains(primaryApp.toLayerName()) && subject.isVisible
+ }
+ .mapNotNull { primaryApp -> primaryApp.layer.visibleRegion }
+ .toTypedArray()
val primaryAppRegionArea = RegionSubject(primaryAppRegions, it.timestamp)
it.visibleRegion(secondaryApp).notOverlaps(primaryAppRegionArea.region)
@@ -102,10 +104,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
index a5ad97d..d1ca9ea 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
@@ -37,7 +36,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) :
+open class CopyContentInSplitBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val textEditApp = SplitScreenUtils.getIme(instrumentation)
protected val magnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
@@ -64,7 +63,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
open fun cujCompleted() {
@@ -74,8 +72,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
index fa6a4bf..73acb1f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -37,7 +36,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScreenBase(flicker) {
+open class DismissSplitScreenByDividerBenchmark(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
@@ -70,7 +70,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
@@ -78,8 +77,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
index d2beb67..86ffd2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenDismissed
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -37,7 +36,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest) :
+open class DismissSplitScreenByGoHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -57,7 +56,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
@@ -65,8 +63,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
index e95fd94..dfde3b6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
@@ -38,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) :
+open class DragDividerToResizeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -60,7 +59,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
open fun cujCompleted() {
@@ -71,8 +69,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 63b74e2..d13e413 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -40,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: FlickerTest) :
+open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
@@ -72,7 +71,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() =
@@ -86,11 +84,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
index e94da87..1d41669 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -40,8 +39,9 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker: FlickerTest) :
- SplitScreenBase(flicker) {
+open class EnterSplitScreenByDragFromNotificationBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
protected val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -69,7 +69,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() =
@@ -83,11 +82,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index f41117f..b4bafa7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -40,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) :
+open class EnterSplitScreenByDragFromShortcutBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
@Before
fun before() {
@@ -72,7 +71,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() =
@@ -86,11 +84,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index 12f610b..da44ecd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -40,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: FlickerTest) :
+open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -67,7 +66,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() =
@@ -86,10 +84,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
index 77818d3..af06d6d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -37,7 +36,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTest) :
+open class EnterSplitScreenFromOverviewBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -66,7 +65,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
@@ -74,8 +72,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index 6ff2290..23156b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -16,15 +16,14 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
@@ -40,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTest) :
+open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -136,7 +135,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
open fun cujCompleted() {
@@ -147,11 +145,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
index 400adea..2d810d3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -38,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: FlickerTest) :
+open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
@@ -65,7 +64,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
@@ -73,11 +71,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
index 1ec4340..f6df1e4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -38,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest) :
+open class SwitchBackToSplitFromHomeBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -63,7 +62,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
@@ -71,11 +69,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
index 9757153..ba46bdc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -16,14 +16,13 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitScreenEntered
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
@@ -38,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTest) :
+open class SwitchBackToSplitFromRecentBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
@@ -63,7 +62,6 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui")
@Presubmit
@Test
fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
@@ -71,11 +69,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
index c19a38d..0d871e5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -16,13 +16,12 @@
package com.android.wm.shell.flicker.splitscreen.benchmark
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
@@ -36,7 +35,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) :
+open class SwitchBetweenSplitPairsBenchmark(override val flicker: LegacyFlickerTest) :
SplitScreenBase(flicker) {
protected val thirdApp = SplitScreenUtils.getIme(instrumentation)
protected val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
@@ -66,13 +65,11 @@
}
@PlatinumTest(focusArea = "sysui")
- @IwTest(focusArea = "sysui") @Presubmit @Test open fun cujCompleted() {}
+ @Presubmit @Test open fun cujCompleted() {}
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
index 5f16e5b..7952b71 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
@@ -19,8 +19,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.SplitScreenBase
import com.android.wm.shell.flicker.splitscreen.SplitScreenUtils
@@ -33,11 +33,11 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class UnlockKeyguardToSplitScreenBenchmark(override val flicker: FlickerTest) :
- SplitScreenBase(flicker) {
+open class UnlockKeyguardToSplitScreenBenchmark(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
protected val thisTransition: FlickerBuilder.() -> Unit
get() = {
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+ setup { SplitScreenUtils.enterSplitViaIntent(wmHelper, primaryApp, secondaryApp) }
transitions {
device.sleep()
wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
@@ -58,10 +58,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
index 8278c67..0dc16f4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/BubbleOverflowTest.java
@@ -64,18 +64,27 @@
}
@Test
- public void test_initialize() {
+ public void test_initialize_forStack() {
assertThat(mOverflow.getExpandedView()).isNull();
- mOverflow.initialize(mBubbleController);
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
assertThat(mOverflow.getExpandedView()).isNotNull();
assertThat(mOverflow.getExpandedView().getBubbleKey()).isEqualTo(BubbleOverflow.KEY);
+ assertThat(mOverflow.getBubbleBarExpandedView()).isNull();
+ }
+
+ @Test
+ public void test_initialize_forBubbleBar() {
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ true);
+
+ assertThat(mOverflow.getBubbleBarExpandedView()).isNotNull();
+ assertThat(mOverflow.getExpandedView()).isNull();
}
@Test
public void test_cleanUpExpandedState() {
- mOverflow.createExpandedView();
+ mOverflow.initialize(mBubbleController, /* forBubbleBar= */ false);
assertThat(mOverflow.getExpandedView()).isNotNull();
mOverflow.cleanUpExpandedState();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
deleted file mode 100644
index 58e91cb..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.kidsmode;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-
-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.Optional;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KidsModeTaskOrganizerTest extends ShellTestCase {
- @Mock private ITaskOrganizerController mTaskOrganizerController;
- @Mock private Context mContext;
- @Mock private Handler mHandler;
- @Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private ShellExecutor mTestExecutor;
- @Mock private DisplayController mDisplayController;
- @Mock private SurfaceControl mLeash;
- @Mock private WindowContainerToken mToken;
- @Mock private WindowContainerTransaction mTransaction;
- @Mock private KidsModeSettingsObserver mObserver;
- @Mock private ShellInit mShellInit;
- @Mock private ShellCommandHandler mShellCommandHandler;
- @Mock private DisplayInsetsController mDisplayInsetsController;
- @Mock private Resources mResources;
-
- KidsModeTaskOrganizer mOrganizer;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- try {
- doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
- .when(mTaskOrganizerController).registerTaskOrganizer(any());
- } catch (RemoteException e) {
- }
- // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
- doReturn(mResources).when(mContext).getResources();
- final KidsModeTaskOrganizer kidsModeTaskOrganizer = new KidsModeTaskOrganizer(mContext,
- mShellInit, mShellCommandHandler, mTaskOrganizerController, mSyncTransactionQueue,
- mDisplayController, mDisplayInsetsController, Optional.empty(), Optional.empty(),
- mObserver, mTestExecutor, mHandler);
- mOrganizer = spy(kidsModeTaskOrganizer);
- doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
- doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
- }
-
- @Test
- public void instantiateController_addInitCallback() {
- verify(mShellInit, times(1)).addInitCallback(any(), any());
- }
-
- @Test
- public void testKidsModeOn() {
- doReturn(true).when(mObserver).isEnabled();
-
- mOrganizer.updateKidsModeState();
-
- verify(mOrganizer, times(1)).enable();
- verify(mOrganizer, times(1)).registerOrganizer();
- verify(mOrganizer, times(1)).createRootTask(
- eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
- verify(mOrganizer, times(1))
- .setOrientationRequestPolicy(eq(true), any(), any());
-
- final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
- WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
- mOrganizer.onTaskAppeared(rootTask, mLeash);
-
- assertThat(mOrganizer.mLaunchRootLeash).isEqualTo(mLeash);
- assertThat(mOrganizer.mLaunchRootTask).isEqualTo(rootTask);
- }
-
- @Test
- public void testKidsModeOff() {
- doReturn(true).when(mObserver).isEnabled();
- mOrganizer.updateKidsModeState();
- final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
- WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
- mOrganizer.onTaskAppeared(rootTask, mLeash);
-
- doReturn(false).when(mObserver).isEnabled();
- mOrganizer.updateKidsModeState();
-
- verify(mOrganizer, times(1)).disable();
- verify(mOrganizer, times(1)).unregisterOrganizer();
- verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
- verify(mOrganizer, times(1))
- .setOrientationRequestPolicy(eq(false), any(), any());
- assertThat(mOrganizer.mLaunchRootLeash).isNull();
- assertThat(mOrganizer.mLaunchRootTask).isNull();
- }
-
- private ActivityManager.RunningTaskInfo createTaskInfo(
- int taskId, int windowingMode, IBinder cookies) {
- ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
- taskInfo.taskId = taskId;
- taskInfo.token = mToken;
- taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
- final ArrayList<IBinder> launchCookies = new ArrayList<>();
- if (cookies != null) {
- launchCookies.add(cookies);
- }
- taskInfo.launchCookies = launchCookies;
- return taskInfo;
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
index 4d7e9e4..cc9e26b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
@@ -18,6 +18,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -26,10 +29,13 @@
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import java.util.Set;
@@ -42,6 +48,10 @@
public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
private PhonePipKeepClearAlgorithm mPipKeepClearAlgorithm;
+
+ @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
+ @Mock private PipBoundsState mMockPipBoundsState;
+
private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
@Before
@@ -73,7 +83,6 @@
@Test
public void findUnoccludedPosition_withCollidingUnrestrictedKeepClearArea_moveBounds() {
- // TODO(b/183746978): update this test to accommodate for the updated algorithm
final Rect inBounds = new Rect(0, 0, 100, 100);
final Rect keepClearRect = new Rect(50, 50, 150, 150);
@@ -93,4 +102,202 @@
assertEquals(inBounds, outBounds);
}
+
+ @Test
+ public void adjust_withCollidingRestrictedKeepClearArea_moveBounds() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertFalse(outBounds.contains(keepClearRect));
+ }
+
+ @Test
+ public void adjust_withNonCollidingRestrictedKeepClearArea_boundsUnchanged() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertFalse(outBounds.contains(keepClearRect));
+ }
+
+ @Test
+ public void adjust_withCollidingRestrictedKeepClearArea_whileStashed_boundsUnchanged() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(50, 50, 150, 150);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.isStashed()).thenReturn(true);
+ when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(pipBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_withNonCollidingRestrictedKeepClearArea_whileStashed_boundsUnchanged() {
+ final Rect pipBounds = new Rect(0, 0, 100, 100);
+ final Rect keepClearRect = new Rect(100, 100, 150, 150);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.isStashed()).thenReturn(true);
+ when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(pipBounds, outBounds);
+ }
+
+ @Test
+ public void adjust_aboveDisplayBounds_onLeftEdge_appliesBottomLeftGravity() {
+ final Rect pipBounds = new Rect(
+ 0, DISPLAY_BOUNDS.top - 50, 100, DISPLAY_BOUNDS.top + 50);
+ final Rect expected = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+ when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(0f);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
+
+ @Test
+ public void adjust_belowDisplayBounds_onLeftEdge_appliesBottomLeftGravity() {
+ final Rect pipBounds = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 50, 100, DISPLAY_BOUNDS.bottom + 50);
+ final Rect expected = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+ when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(3f);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
+
+ @Test
+ public void adjust_aboveDisplayBounds_onRightEdge_appliesBottomRightGravity() {
+ final Rect pipBounds = new Rect(
+ DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.top - 50,
+ DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.top + 50);
+ final Rect expected = new Rect(
+ DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
+ DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+ when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(1f);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
+
+ @Test
+ public void adjust_belowDisplayBounds_onRightEdge_appliesBottomRightGravity() {
+ final Rect pipBounds = new Rect(
+ DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 50,
+ DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom + 50);
+ final Rect expected = new Rect(
+ DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
+ DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+ when(mMockPipBoundsAlgorithm.getSnapFraction(any(Rect.class))).thenReturn(2f);
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
+
+ @Test
+ public void adjust_whileStashed_aboveDisplayBounds_alignsToBottomInset() {
+ final Rect pipBounds = new Rect(
+ 0, DISPLAY_BOUNDS.top - 50, 100, DISPLAY_BOUNDS.top + 50);
+ final Rect expected = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.isStashed()).thenReturn(true);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
+
+ @Test
+ public void adjust_whileStashed_belowDisplayBounds_alignsToBottomInset() {
+ final Rect pipBounds = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 50, 100, DISPLAY_BOUNDS.bottom + 50);
+ final Rect expected = new Rect(
+ 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
+ when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+ when(mMockPipBoundsState.isStashed()).thenReturn(true);
+ doAnswer(invocation -> {
+ Rect arg0 = invocation.getArgument(0);
+ arg0.set(DISPLAY_BOUNDS);
+ return null;
+ }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+ final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+ mMockPipBoundsState, mMockPipBoundsAlgorithm);
+
+ assertEquals(expected, outBounds);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index b00a60c..5efd9ad 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -76,6 +76,7 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -105,6 +106,7 @@
@Mock private WindowDecorViewModel mWindowDecorViewModel;
@Mock private ShellExecutor mMainExecutor;
@Mock private LaunchAdjacentController mLaunchAdjacentController;
+ @Mock private DefaultMixedHandler mMixedHandler;
private SplitLayout mSplitLayout;
private MainStage mMainStage;
private SideStage mSideStage;
@@ -136,6 +138,7 @@
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
mTransactionPool, mMainExecutor, Optional.empty(),
mLaunchAdjacentController, Optional.empty());
+ mStageCoordinator.setMixedHandler(mMixedHandler);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 28bda72..fa9447a 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -232,6 +232,7 @@
"tests/AssetManager2_bench.cpp",
"tests/AttributeResolution_bench.cpp",
"tests/CursorWindow_bench.cpp",
+ "tests/Generic_bench.cpp",
"tests/SparseEntry_bench.cpp",
"tests/Theme_bench.cpp",
],
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index e3f0c8f..dcbaaec 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1094,14 +1094,16 @@
base::expected<const std::vector<uint32_t>*, NullOrIOError> AssetManager2::GetBagResIdStack(
uint32_t resid) const {
- auto [it, inserted] = cached_bag_resid_stacks_.try_emplace(resid);
- if (inserted) {
- // This is a new entry in the cache, need to populate it.
- if (auto maybe_bag = GetBag(resid, it->second); UNLIKELY(IsIOError(maybe_bag))) {
- cached_bag_resid_stacks_.erase(it);
- return base::unexpected(maybe_bag.error());
- }
+ auto it = cached_bag_resid_stacks_.find(resid);
+ if (it != cached_bag_resid_stacks_.end()) {
+ return &it->second;
}
+ std::vector<uint32_t> stacks;
+ if (auto maybe_bag = GetBag(resid, stacks); UNLIKELY(IsIOError(maybe_bag))) {
+ return base::unexpected(maybe_bag.error());
+ }
+
+ it = cached_bag_resid_stacks_.emplace(resid, std::move(stacks)).first;
return &it->second;
}
@@ -1119,8 +1121,10 @@
}
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
- auto [resid_stacks_it, _] = cached_bag_resid_stacks_.try_emplace(resid);
- resid_stacks_it->second.clear();
+ auto resid_stacks_it = cached_bag_resid_stacks_.find(resid);
+ if (resid_stacks_it == cached_bag_resid_stacks_.end()) {
+ resid_stacks_it = cached_bag_resid_stacks_.emplace(resid, std::vector<uint32_t>{}).first;
+ }
const auto bag = GetBag(resid, resid_stacks_it->second);
if (UNLIKELY(IsIOError(bag))) {
cached_bag_resid_stacks_.erase(resid_stacks_it);
@@ -1438,25 +1442,40 @@
}
void AssetManager2::InvalidateCaches(uint32_t diff) {
- cached_bag_resid_stacks_.clear();
+ cached_resolved_values_.clear();
if (diff == 0xffffffffu) {
// Everything must go.
cached_bags_.clear();
+ cached_bag_resid_stacks_.clear();
return;
}
// Be more conservative with what gets purged. Only if the bag has other possible
// variations with respect to what changed (diff) should we remove it.
- for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
- if (diff & iter->second->type_spec_flags) {
- iter = cached_bags_.erase(iter);
+ for (auto stack_it = cached_bag_resid_stacks_.begin();
+ stack_it != cached_bag_resid_stacks_.end();) {
+ const auto it = cached_bags_.find(stack_it->first);
+ if (it == cached_bags_.end()) {
+ stack_it = cached_bag_resid_stacks_.erase(stack_it);
+ } else if ((diff & it->second->type_spec_flags) != 0) {
+ cached_bags_.erase(it);
+ stack_it = cached_bag_resid_stacks_.erase(stack_it);
} else {
- ++iter;
+ ++stack_it; // Keep the item in both caches.
}
}
- cached_resolved_values_.clear();
+ // Need to ensure that both bag caches are consistent, as we populate them in the same function.
+ // Iterate over the cached bags to erase the items without the corresponding resid_stack cache
+ // items.
+ for (auto it = cached_bags_.begin(); it != cached_bags_.end();) {
+ if ((diff & it->second->type_spec_flags) != 0) {
+ it = cached_bags_.erase(it);
+ } else {
+ ++it;
+ }
+ }
}
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
diff --git a/libs/androidfw/tests/Generic_bench.cpp b/libs/androidfw/tests/Generic_bench.cpp
new file mode 100644
index 0000000..4c978e8
--- /dev/null
+++ b/libs/androidfw/tests/Generic_bench.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <map>
+#include <unordered_map>
+
+#include "benchmark/benchmark.h"
+
+namespace android {
+
+template <class Map = std::unordered_map<uint32_t, std::vector<uint32_t>>>
+static Map prepare_map() {
+ Map map;
+ std::vector<uint32_t> vec;
+ for (int i = 0; i < 1000; ++i) {
+ map.emplace(i, vec);
+ }
+ return map;
+}
+
+static void BM_hashmap_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<>();
+ auto val = map.size() - 1;
+ std::vector<uint32_t> vec;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.emplace(val, vec));
+ }
+}
+BENCHMARK(BM_hashmap_emplace_same);
+static void BM_hashmap_try_emplace_same(benchmark::State& state) {
+ auto map = prepare_map();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.try_emplace(val));
+ }
+}
+BENCHMARK(BM_hashmap_try_emplace_same);
+static void BM_hashmap_find(benchmark::State& state) {
+ auto map = prepare_map<>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.find(val));
+ }
+}
+BENCHMARK(BM_hashmap_find);
+
+static void BM_hashmap_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.emplace(i++, vec);
+ }
+}
+BENCHMARK(BM_hashmap_emplace_diff);
+static void BM_hashmap_try_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.try_emplace(i++);
+ }
+}
+BENCHMARK(BM_hashmap_try_emplace_diff);
+static void BM_hashmap_find_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ if (map.find(i++) == map.end()) {
+ map.emplace(i - 1, vec);
+ }
+ }
+}
+BENCHMARK(BM_hashmap_find_emplace_diff);
+
+static void BM_treemap_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ std::vector<uint32_t> vec;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.emplace(val, vec));
+ }
+}
+BENCHMARK(BM_treemap_emplace_same);
+static void BM_treemap_try_emplace_same(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.try_emplace(val));
+ }
+}
+BENCHMARK(BM_treemap_try_emplace_same);
+static void BM_treemap_find(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ auto val = map.size() - 1;
+ for (auto&& _ : state) {
+ benchmark::DoNotOptimize(map.find(val));
+ }
+}
+BENCHMARK(BM_treemap_find);
+
+static void BM_treemap_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.emplace(i++, vec);
+ }
+}
+BENCHMARK(BM_treemap_emplace_diff);
+static void BM_treemap_try_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ auto i = map.size();
+ for (auto&& _ : state) {
+ map.try_emplace(i++);
+ }
+}
+BENCHMARK(BM_treemap_try_emplace_diff);
+static void BM_treemap_find_emplace_diff(benchmark::State& state) {
+ auto map = prepare_map();
+ std::vector<uint32_t> vec;
+ auto i = map.size();
+ for (auto&& _ : state) {
+ if (map.find(i++) == map.end()) {
+ map.emplace(i - 1, vec);
+ }
+ }
+}
+BENCHMARK(BM_treemap_find_emplace_diff);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index db58147..b5e6f94 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -514,6 +514,7 @@
"canvas/CanvasOpRasterizer.cpp",
"effects/StretchEffect.cpp",
"effects/GainmapRenderer.cpp",
+ "pipeline/skia/BackdropFilterDrawable.cpp",
"pipeline/skia/HolePunch.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1c39db3..1dd22cf 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -260,6 +260,12 @@
pushStagingDisplayListChanges(observer, info);
}
+ // always damageSelf when filtering backdrop content, or else the BackdropFilterDrawable will
+ // get a wrong snapshot of previous content.
+ if (mProperties.layerProperties().getBackdropImageFilter()) {
+ damageSelf(info);
+ }
+
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList.hasFunctor();
mHasHolePunches = mDisplayList.hasHolePunches();
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 0589f13..c537123 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -55,6 +55,12 @@
return true;
}
+bool LayerProperties::setBackdropImageFilter(SkImageFilter* imageFilter) {
+ if (mBackdropImageFilter.get() == imageFilter) return false;
+ mBackdropImageFilter = sk_ref_sp(imageFilter);
+ return true;
+}
+
bool LayerProperties::setFromPaint(const SkPaint* paint) {
bool changed = false;
changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
@@ -70,6 +76,7 @@
setXferMode(other.xferMode());
setColorFilter(other.getColorFilter());
setImageFilter(other.getImageFilter());
+ setBackdropImageFilter(other.getBackdropImageFilter());
mStretchEffect = other.mStretchEffect;
return *this;
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 064ba7a..e358b57 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -97,8 +97,12 @@
bool setImageFilter(SkImageFilter* imageFilter);
+ bool setBackdropImageFilter(SkImageFilter* imageFilter);
+
SkImageFilter* getImageFilter() const { return mImageFilter.get(); }
+ SkImageFilter* getBackdropImageFilter() const { return mBackdropImageFilter.get(); }
+
const StretchEffect& getStretchEffect() const { return mStretchEffect; }
StretchEffect& mutableStretchEffect() { return mStretchEffect; }
@@ -129,6 +133,7 @@
SkBlendMode mMode;
sk_sp<SkColorFilter> mColorFilter;
sk_sp<SkImageFilter> mImageFilter;
+ sk_sp<SkImageFilter> mBackdropImageFilter;
StretchEffect mStretchEffect;
};
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index aeaa171..4c9a23d 100644
--- a/libs/hwui/jni/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -96,17 +96,33 @@
sk_sp<SkColorSpace> decodeColorSpace =
mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr);
SkBitmap bm;
- HeapAllocator heapAlloc;
- if (!mGainmapBRD->decodeRegion(&bm, &heapAlloc, desiredSubset, sampleSize, decodeColorType,
- requireUnpremul, decodeColorSpace)) {
- ALOGE("Error decoding Gainmap region");
- return false;
- }
- sk_sp<Bitmap> nativeBitmap(heapAlloc.getStorageObjAndReset());
+ // Because we must match the dimensions of the base bitmap, we always use a
+ // recycling allocator even though we are allocating a new bitmap. This is to ensure
+ // that if a recycled bitmap was used for the base image that we match the relative
+ // dimensions of that base image. The behavior of BRD here is:
+ // if inBitmap is specified -> output dimensions are always equal to the inBitmap's
+ // if no bitmap is reused -> output dimensions are the intersect of the desiredSubset &
+ // the image bounds
+ // The handling of the above conditionals are baked into the desiredSubset, so we
+ // simply need to ensure that the resulting bitmap is the exact same width/height as
+ // the specified desiredSubset regardless of the intersection to the image bounds.
+ // kPremul_SkAlphaType is used just as a placeholder as it doesn't change the underlying
+ // allocation type. RecyclingClippingPixelAllocator will populate this with the
+ // actual alpha type in either allocPixelRef() or copyIfNecessary()
+ sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(
+ SkImageInfo::Make(desiredSubset.width(), desiredSubset.height(), decodeColorType,
+ kPremul_SkAlphaType, decodeColorSpace));
if (!nativeBitmap) {
ALOGE("OOM allocating Bitmap for Gainmap");
return false;
}
+ RecyclingClippingPixelAllocator allocator(nativeBitmap.get(), false);
+ if (!mGainmapBRD->decodeRegion(&bm, &allocator, desiredSubset, sampleSize, decodeColorType,
+ requireUnpremul, decodeColorSpace)) {
+ ALOGE("Error decoding Gainmap region");
+ return false;
+ }
+ allocator.copyIfNecessary();
auto gainmap = sp<uirenderer::Gainmap>::make();
if (!gainmap) {
ALOGE("OOM allocating Gainmap");
@@ -238,13 +254,11 @@
// Recycle a bitmap if possible.
android::Bitmap* recycledBitmap = nullptr;
- size_t recycledBytes = 0;
if (javaBitmap) {
recycledBitmap = &bitmap::toBitmap(inBitmapHandle);
if (recycledBitmap->isImmutable()) {
ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
}
- recycledBytes = recycledBitmap->getAllocationByteCount();
}
auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle);
@@ -263,7 +277,7 @@
// Set up the pixel allocator
skia::BRDAllocator* allocator = nullptr;
- RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
+ RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap);
HeapAllocator heapAlloc;
if (javaBitmap) {
allocator = &recycleAlloc;
@@ -277,7 +291,7 @@
decodeColorType, colorSpace);
// Decode the region.
- SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
+ const SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
SkBitmap bitmap;
if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize,
decodeColorType, requireUnpremul, decodeColorSpace)) {
@@ -307,10 +321,27 @@
GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType));
}
+ if (javaBitmap) {
+ recycleAlloc.copyIfNecessary();
+ }
+
sp<uirenderer::Gainmap> gainmap;
bool hasGainmap = brd->hasGainmap();
if (hasGainmap) {
- SkIRect gainmapSubset = brd->calculateGainmapRegion(subset);
+ SkIRect adjustedSubset{};
+ if (javaBitmap) {
+ // Clamp to the width/height of the recycled bitmap in case the reused bitmap
+ // was too small for the specified rectangle, in which case we need to clip
+ adjustedSubset = SkIRect::MakeXYWH(inputX, inputY,
+ std::min(subset.width(), recycledBitmap->width()),
+ std::min(subset.height(), recycledBitmap->height()));
+ } else {
+ // We are not recycling, so use the decoded width/height for calculating the gainmap
+ // subset instead to ensure the gainmap region proportionally matches
+ adjustedSubset = SkIRect::MakeXYWH(std::max(0, inputX), std::max(0, inputY),
+ bitmap.width(), bitmap.height());
+ }
+ SkIRect gainmapSubset = brd->calculateGainmapRegion(adjustedSubset);
if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) {
// If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap
hasGainmap = false;
@@ -319,7 +350,6 @@
// If we may have reused a bitmap, we need to indicate that the pixels have changed.
if (javaBitmap) {
- recycleAlloc.copyIfNecessary();
if (hasGainmap) {
recycledBitmap->setGainmap(std::move(gainmap));
}
@@ -331,6 +361,7 @@
if (!requireUnpremul) {
bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
}
+
if (isHardware) {
sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap);
if (hasGainmap) {
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index 914266d..78b4f7b 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -620,13 +620,13 @@
////////////////////////////////////////////////////////////////////////////////
-RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator(
- android::Bitmap* recycledBitmap, size_t recycledBytes)
- : mRecycledBitmap(recycledBitmap)
- , mRecycledBytes(recycledBytes)
- , mSkiaBitmap(nullptr)
- , mNeedsCopy(false)
-{}
+RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
+ bool mustMatchColorType)
+ : mRecycledBitmap(recycledBitmap)
+ , mRecycledBytes(recycledBitmap ? recycledBitmap->getAllocationByteCount() : 0)
+ , mSkiaBitmap(nullptr)
+ , mNeedsCopy(false)
+ , mMustMatchColorType(mustMatchColorType) {}
RecyclingClippingPixelAllocator::~RecyclingClippingPixelAllocator() {}
@@ -637,10 +637,16 @@
LOG_ALWAYS_FATAL_IF(!bitmap);
mSkiaBitmap = bitmap;
- // This behaves differently than the RecyclingPixelAllocator. For backwards
- // compatibility, the original color type of the recycled bitmap must be maintained.
- if (mRecycledBitmap->info().colorType() != bitmap->colorType()) {
- return false;
+ if (mMustMatchColorType) {
+ // This behaves differently than the RecyclingPixelAllocator. For backwards
+ // compatibility, the original color type of the recycled bitmap must be maintained.
+ if (mRecycledBitmap->info().colorType() != bitmap->colorType()) {
+ ALOGW("recycled color type %d != bitmap color type %d",
+ mRecycledBitmap->info().colorType(), bitmap->colorType());
+ return false;
+ }
+ } else {
+ mRecycledBitmap->reconfigure(mRecycledBitmap->info().makeColorType(bitmap->colorType()));
}
// The Skia bitmap specifies the width and height needed by the decoder.
@@ -695,7 +701,7 @@
void RecyclingClippingPixelAllocator::copyIfNecessary() {
if (mNeedsCopy) {
mRecycledBitmap->ref();
- SkPixelRef* recycledPixels = mRecycledBitmap;
+ android::Bitmap* recycledPixels = mRecycledBitmap;
void* dst = recycledPixels->pixels();
const size_t dstRowBytes = mRecycledBitmap->rowBytes();
const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(),
@@ -708,6 +714,8 @@
dst = reinterpret_cast<void*>(
reinterpret_cast<uint8_t*>(dst) + dstRowBytes);
}
+ recycledPixels->setAlphaType(mSkiaBitmap->alphaType());
+ recycledPixels->setColorSpace(mSkiaBitmap->refColorSpace());
recycledPixels->notifyPixelsChanged();
recycledPixels->unref();
}
diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index 24f9e82..b9fff36 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -125,14 +125,6 @@
static jobject createBitmapRegionDecoder(JNIEnv* env,
android::BitmapRegionDecoderWrapper* bitmap);
- /**
- * Given a bitmap we natively allocate a memory block to store the contents
- * of that bitmap. The memory is then attached to the bitmap via an
- * SkPixelRef, which ensures that upon deletion the appropriate caches
- * are notified.
- */
- static bool allocatePixels(JNIEnv* env, SkBitmap* bitmap);
-
/** Copy the colors in colors[] to the bitmap, convert to the correct
format along the way.
Whether to use premultiplied pixels is determined by dstBitmap's alphaType.
@@ -222,9 +214,8 @@
*/
class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator {
public:
-
RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
- size_t recycledBytes);
+ bool mustMatchColorType = true);
~RecyclingClippingPixelAllocator();
@@ -252,6 +243,7 @@
const size_t mRecycledBytes;
SkBitmap* mSkiaBitmap;
bool mNeedsCopy;
+ const bool mMustMatchColorType;
};
class AshmemPixelAllocator : public SkBitmap::Allocator {
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 8c7b9a4..2a218a2 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -243,6 +243,13 @@
return SET_AND_DIRTY(mutateLayerProperties().setImageFilter, imageFilter, RenderNode::GENERIC);
}
+static jboolean android_view_RenderNode_setBackdropRenderEffect(
+ CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong renderEffectPtr) {
+ SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setBackdropImageFilter, imageFilter,
+ RenderNode::GENERIC);
+}
+
static jboolean android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
bool hasOverlappingRendering) {
return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
@@ -792,6 +799,8 @@
{"nSetAlpha", "(JF)Z", (void*)android_view_RenderNode_setAlpha},
{"nSetRenderEffect", "(JJ)Z", (void*)android_view_RenderNode_setRenderEffect},
+ {"nSetBackdropRenderEffect", "(JJ)Z",
+ (void*)android_view_RenderNode_setBackdropRenderEffect},
{"nSetHasOverlappingRendering", "(JZ)Z",
(void*)android_view_RenderNode_setHasOverlappingRendering},
{"nSetUsageHint", "(JI)V", (void*)android_view_RenderNode_setUsageHint},
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
new file mode 100644
index 0000000..ffad699
--- /dev/null
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BackdropFilterDrawable.h"
+
+#include <SkImage.h>
+#include <SkSurface.h>
+
+#include "RenderNode.h"
+#include "RenderNodeDrawable.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+BackdropFilterDrawable::~BackdropFilterDrawable() {}
+
+bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties,
+ int backdropImageWidth, int backdropImageHeight) {
+ // the drawing bounds for blurred content.
+ mDstBounds.setWH(properties.getWidth(), properties.getHeight());
+
+ float alphaMultiplier = 1.0f;
+ RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
+
+ // get proper subset for previous content.
+ canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds);
+ SkRect imageSubset(mImageSubset);
+ // ensure the subset is inside bounds of previous content.
+ if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) {
+ return false;
+ }
+
+ // correct the drawing bounds if subset was changed.
+ if (mImageSubset != imageSubset) {
+ SkMatrix inverse;
+ if (canvas->getTotalMatrix().invert(&inverse)) {
+ inverse.mapRect(&mDstBounds, mImageSubset);
+ }
+ }
+
+ // follow the alpha from the target RenderNode.
+ mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
+ return true;
+}
+
+void BackdropFilterDrawable::onDraw(SkCanvas* canvas) {
+ const RenderProperties& properties = mTargetRenderNode->properties();
+ auto* backdropFilter = properties.layerProperties().getBackdropImageFilter();
+ auto* surface = canvas->getSurface();
+ if (!backdropFilter || !surface) {
+ return;
+ }
+
+ auto backdropImage = surface->makeImageSnapshot();
+ // sync necessary properties from target RenderNode.
+ if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) {
+ return;
+ }
+
+ auto imageSubset = mImageSubset.roundOut();
+ backdropImage =
+ backdropImage->makeWithFilter(canvas->recordingContext(), backdropFilter, imageSubset,
+ imageSubset, &mOutSubset, &mOutOffset);
+ canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds,
+ SkSamplingOptions(SkFilterMode::kLinear), &mPaint,
+ SkCanvas::kStrict_SrcRectConstraint);
+}
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
new file mode 100644
index 0000000..9e35837
--- /dev/null
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <SkCanvas.h>
+#include <SkDrawable.h>
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+class RenderNode;
+class RenderProperties;
+
+namespace skiapipeline {
+
+/**
+ * This drawable captures it's backdrop content and render it with a
+ * image filter.
+ */
+class BackdropFilterDrawable : public SkDrawable {
+public:
+ BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas)
+ : mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {}
+
+ ~BackdropFilterDrawable();
+
+private:
+ RenderNode* mTargetRenderNode;
+ SkPaint mPaint;
+
+ SkRect mDstBounds;
+ SkRect mImageSubset;
+ SkIRect mOutSubset;
+ SkIPoint mOutOffset;
+
+ /**
+ * Check all necessary properties before actual drawing.
+ * Return true if ready to draw.
+ */
+ bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth,
+ int backdropImageHeight);
+
+protected:
+ void onDraw(SkCanvas* canvas) override;
+
+ virtual SkRect onGetBounds() override { return mBounds; }
+ const SkRect mBounds;
+};
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index da4f66d..9d72c23 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -362,7 +362,7 @@
}
void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier) {
+ float* alphaMultiplier, bool ignoreLayer) {
if (properties.getLeft() != 0 || properties.getTop() != 0) {
canvas->translate(properties.getLeft(), properties.getTop());
}
@@ -378,7 +378,8 @@
canvas->concat(*properties.getTransformMatrix());
}
}
- if (Properties::getStretchEffectBehavior() == StretchEffectBehavior::UniformScale) {
+ if (Properties::getStretchEffectBehavior() == StretchEffectBehavior::UniformScale &&
+ !ignoreLayer) {
const StretchEffect& stretch = properties.layerProperties().getStretchEffect();
if (!stretch.isEmpty()) {
canvas->concat(
@@ -388,10 +389,10 @@
const bool isLayer = properties.effectiveLayerType() != LayerType::None;
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
- if (isLayer) {
+ if (isLayer && !ignoreLayer) {
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
+ if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering()) || ignoreLayer) {
*alphaMultiplier = properties.getAlpha();
} else {
// savelayer needed to create an offscreen buffer
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index c7582e7..818ac45 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -120,7 +120,7 @@
* Applies the rendering properties of a view onto a SkCanvas.
*/
static void setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier);
+ float* alphaMultiplier, bool ignoreLayer = false);
/**
* Stores transform on the canvas at time of recording and is used for
@@ -149,6 +149,11 @@
* display list that is searched for any render nodes with getProjectBackwards==true
*/
SkiaDisplayList* mProjectedDisplayList = nullptr;
+
+ /**
+ * Allow BackdropFilterDrawable to apply same render properties onto SkCanvas.
+ */
+ friend class BackdropFilterDrawable;
};
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 3ca7eeb..58c14c1 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -37,6 +37,7 @@
#include "NinePatchUtils.h"
#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/BackdropFilterDrawable.h"
#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
#include "pipeline/skia/GLFunctorDrawable.h"
#include "pipeline/skia/VkFunctorDrawable.h"
@@ -168,6 +169,14 @@
// Put Vulkan WebViews with non-rectangular clips in a HW layer
renderNode->mutateStagingProperties().setClipMayBeComplex(mRecorder.isClipMayBeComplex());
}
+
+ // draw backdrop filter drawable if needed.
+ if (renderNode->stagingProperties().layerProperties().getBackdropImageFilter()) {
+ auto* backdropFilterDrawable =
+ mDisplayList->allocateDrawable<BackdropFilterDrawable>(renderNode, asSkCanvas());
+ drawDrawable(backdropFilterDrawable);
+ }
+
drawDrawable(&renderNodeDrawable);
// use staging property, since recording on UI thread
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index dd95c4f..1e055c2 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -14,20 +14,22 @@
* limitations under the License.
*/
-#include <VectorDrawable.h>
-#include <gtest/gtest.h>
-
#include <SkBlendMode.h>
#include <SkClipStack.h>
#include <SkSurface_Base.h>
+#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <include/effects/SkImageFilters.h>
#include <string.h>
+
#include "AnimationContext.h"
#include "DamageAccumulator.h"
#include "FatalTestCanvas.h"
#include "IContextFactory.h"
-#include "hwui/Paint.h"
#include "RecordingCanvas.h"
#include "SkiaCanvas.h"
+#include "hwui/Paint.h"
+#include "pipeline/skia/BackdropFilterDrawable.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
@@ -1211,3 +1213,77 @@
canvas.drawDrawable(&drawable);
EXPECT_EQ(2, canvas.mDrawCounter);
}
+
+// Verify drawing logics for BackdropFilterDrawable
+RENDERTHREAD_TEST(BackdropFilterDrawable, drawing) {
+ static const int CANVAS_WIDTH = 100;
+ static const int CANVAS_HEIGHT = 200;
+ class SimpleTestCanvas : public TestCanvasBase {
+ public:
+ SkRect mDstBounds;
+ SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+ // did nothing.
+ }
+
+ // called when BackdropFilterDrawable is drawn.
+ void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst,
+ const SkSamplingOptions&, const SkPaint*,
+ SrcRectConstraint) override {
+ mDrawCounter++;
+ mDstBounds = dst;
+ }
+ };
+ class SimpleLayer : public SkSurface_Base {
+ public:
+ SimpleLayer()
+ : SkSurface_Base(SkImageInfo::MakeN32Premul(CANVAS_WIDTH, CANVAS_HEIGHT), nullptr) {
+ }
+ virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(CANVAS_WIDTH, CANVAS_HEIGHT);
+ bitmap.setImmutable();
+ return bitmap.asImage();
+ }
+ SkCanvas* onNewCanvas() override { return new SimpleTestCanvas(); }
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
+ bool onCopyOnWrite(ContentChangeMode) override { return true; }
+ void onWritePixels(const SkPixmap&, int x, int y) {}
+ };
+
+ auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ Paint());
+ });
+
+ sk_sp<SkSurface> surface(new SimpleLayer());
+ auto* canvas = reinterpret_cast<SimpleTestCanvas*>(surface->getCanvas());
+ RenderNodeDrawable drawable(node.get(), canvas, true);
+ BackdropFilterDrawable backdropDrawable(node.get(), canvas);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // no backdrop filter, skip drawing.
+ EXPECT_EQ(0, canvas->mDrawCounter);
+
+ sk_sp<SkImageFilter> filter(SkImageFilters::Blur(3, 3, nullptr));
+ node->animatorProperties().mutateLayerProperties().setBackdropImageFilter(filter.get());
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // backdrop filter is set, ok to draw.
+ EXPECT_EQ(1, canvas->mDrawCounter);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds);
+
+ canvas->translate(30, 30);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // the drawable is still visible, ok to draw.
+ EXPECT_EQ(2, canvas->mDrawCounter);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds);
+
+ canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT);
+ canvas->drawDrawable(&drawable);
+ canvas->drawDrawable(&backdropDrawable);
+ // the drawable is invisible, skip drawing.
+ EXPECT_EQ(2, canvas->mDrawCounter);
+}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 9be7728..0eb657a 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -709,7 +709,7 @@
/**
* Returns the Mean Sea Level altitude of this location in meters.
*
- * <p>This is only valid if {@link #hasMslAltitude()} is true.
+ * @throws IllegalStateException if {@link #hasMslAltitude()} is false.
*/
public @FloatRange double getMslAltitudeMeters() {
Preconditions.checkState(hasMslAltitude(),
@@ -744,7 +744,7 @@
* percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
* altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
*
- * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
+ * @throws IllegalStateException if {@link #hasMslAltitudeAccuracy()} is false.
*/
public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
Preconditions.checkState(hasMslAltitudeAccuracy(),
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index f86b9af..23f87ab 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1566,7 +1566,7 @@
FileInputStream in = null;
try {
in = new FileInputStream(fileDescriptor);
- loadAttributes(in, fileDescriptor);
+ loadAttributes(in);
} finally {
closeQuietly(in);
if (isFdDuped) {
@@ -1637,7 +1637,7 @@
mSeekableFileDescriptor = null;
}
}
- loadAttributes(inputStream, null);
+ loadAttributes(inputStream);
}
/**
@@ -1963,7 +1963,7 @@
* This function decides which parser to read the image data according to the given input stream
* type and the content of the input stream.
*/
- private void loadAttributes(@NonNull InputStream in, @Nullable FileDescriptor fd) {
+ private void loadAttributes(@NonNull InputStream in) {
if (in == null) {
throw new NullPointerException("inputstream shouldn't be null");
}
@@ -1993,7 +1993,7 @@
break;
}
case IMAGE_TYPE_HEIF: {
- getHeifAttributes(inputStream, fd);
+ getHeifAttributes(inputStream);
break;
}
case IMAGE_TYPE_ORF: {
@@ -2580,7 +2580,7 @@
} else if (isSeekableFD(in.getFD())) {
mSeekableFileDescriptor = in.getFD();
}
- loadAttributes(in, null);
+ loadAttributes(in);
} finally {
closeQuietly(in);
if (modernFd != null) {
@@ -3068,66 +3068,59 @@
}
}
- private void getHeifAttributes(ByteOrderedDataInputStream in, @Nullable FileDescriptor fd)
- throws IOException {
+ private void getHeifAttributes(ByteOrderedDataInputStream in) throws IOException {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
- if (fd != null) {
- retriever.setDataSource(fd);
- } else {
- retriever.setDataSource(new MediaDataSource() {
- long mPosition;
+ retriever.setDataSource(new MediaDataSource() {
+ long mPosition;
- @Override
- public void close() throws IOException {}
+ @Override
+ public void close() throws IOException {}
- @Override
- public int readAt(long position, byte[] buffer, int offset, int size)
- throws IOException {
- if (size == 0) {
- return 0;
- }
- if (position < 0) {
- return -1;
- }
- try {
- if (mPosition != position) {
- // We don't allow seek to positions after the available bytes,
- // the input stream won't be able to seek back then.
- // However, if we hit an exception before (mPosition set to -1),
- // let it try the seek in hope it might recover.
- if (mPosition >= 0 && position >= mPosition + in.available()) {
- return -1;
- }
- in.seek(position);
- mPosition = position;
- }
-
- // If the read will cause us to go over the available bytes,
- // reduce the size so that we stay in the available range.
- // Otherwise the input stream may not be able to seek back.
- if (size > in.available()) {
- size = in.available();
- }
-
- int bytesRead = in.read(buffer, offset, size);
- if (bytesRead >= 0) {
- mPosition += bytesRead;
- return bytesRead;
- }
- } catch (IOException e) {
- // absorb the exception and fall through to the 'failed read' path below
- }
- mPosition = -1; // need to seek on next read
+ @Override
+ public int readAt(long position, byte[] buffer, int offset, int size)
+ throws IOException {
+ if (size == 0) {
+ return 0;
+ }
+ if (position < 0) {
return -1;
}
+ try {
+ if (mPosition != position) {
+ // We don't allow seek to positions after the available bytes,
+ // the input stream won't be able to seek back then.
+ // However, if we hit an exception before (mPosition set to -1),
+ // let it try the seek in hope it might recover.
+ if (mPosition >= 0 && position >= mPosition + in.available()) {
+ return -1;
+ }
+ in.seek(position);
+ mPosition = position;
+ }
- @Override
- public long getSize() throws IOException {
- return -1;
- }
- });
- }
+ // If the read will cause us to go over the available bytes,
+ // reduce the size so that we stay in the available range.
+ // Otherwise the input stream may not be able to seek back.
+ if (size > in.available()) {
+ size = in.available();
+ }
+
+ int bytesRead = in.read(buffer, offset, size);
+ if (bytesRead >= 0) {
+ mPosition += bytesRead;
+ return bytesRead;
+ }
+ } catch (IOException e) {}
+ mPosition = -1; // need to seek on next read
+ return -1;
+ }
+
+ @Override
+ public long getSize() throws IOException {
+ return -1;
+ }
+ });
String exifOffsetStr = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET);
diff --git a/media/java/android/media/RingtoneSelection.java b/media/java/android/media/RingtoneSelection.java
new file mode 100644
index 0000000..74f7276
--- /dev/null
+++ b/media/java/android/media/RingtoneSelection.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.provider.MediaStore;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Immutable representation a desired ringtone, usually originating from a user preference.
+ * Unlike sound-only Uris, a "silent" setting is an explicit selection value, rather than null.
+ *
+ * <p>This representation can be converted into (or from) a URI form for storing within a string
+ * preference or when using the ringtone picker via {@link RingtoneManager#ACTION_RINGTONE_PICKER}.
+ * It does not carry any actual media data - it only references the components that make
+ * up the preference. Initial selections can be built using {@link RingtoneSelection.Builder}.
+ *
+ * <p>A RingtoneSelection is typically played by passing into a {@link Ringtone.Builder}, and
+ * supplementing with contextual defaults from the application. Bad Uris are handled by the
+ * {@link Ringtone} class - the RingtoneSelection doesn't validate the target of the Uri.
+ *
+ * <p>When a RingtoneSelection is created/loaded, the values of its properties are modified
+ * to be internally consistent and reflect effective values - with the exception of not verifying
+ * the actual URI content. For example, loading a selection Uri that sets a sound source to
+ * {@link #SOUND_SOURCE_URI}, but doesn't also have a sound Uri set, will result in this class
+ * instead returning {@link #SOUND_SOURCE_DEFAULT} from {@link #getSoundSource}.
+ *
+ * <h2>Storing preferences</h2>
+ *
+ * <p>A ringtone preference can have several states: either unset, set to a ringtone selection Uri,
+ * or, from prior to the introduction of {@code RingtoneSelection}, set to a sound-only Uri or
+ * explicitly set to null to indicate silent.
+ *
+ * @hide
+ */
+@TestApi
+public final class RingtoneSelection {
+
+ /**
+ * The sound source was specified but its value was not recognized. This value is used
+ * internally for not stripping unrecognised (possibly future) values during processing.
+ * @hide
+ */
+ public static final int SOUND_SOURCE_UNKNOWN = -1;
+
+ /**
+ * The sound source is not explicitly specified, so it can follow default behavior for its
+ * context.
+ */
+ public static final int SOUND_SOURCE_DEFAULT = 0;
+
+ /**
+ * Sound is explicitly disabled, such as the user having selected "Silent" in the sound picker.
+ */
+ public static final int SOUND_SOURCE_OFF = 1;
+
+ /**
+ * The sound Uri should be used as the source of sound.
+ */
+ public static final int SOUND_SOURCE_URI = 2;
+
+ /**
+ * Directive for how to make sound.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "SOUND_SOURCE_", value = {
+ SOUND_SOURCE_UNKNOWN,
+ SOUND_SOURCE_DEFAULT,
+ SOUND_SOURCE_OFF,
+ SOUND_SOURCE_URI,
+ })
+ public @interface SoundSource {}
+
+ /**
+ * The vibration source was specified but its value was not recognized.
+ * This value is used internally for not stripping unrecognised (possibly
+ * future) values during processing.
+ * @hide
+ */
+ public static final int VIBRATION_SOURCE_UNKNOWN = -1;
+
+ /**
+ * Vibration source is not explicitly specified. If vibration is enabled, this will use the
+ * first available of {@link #VIBRATION_SOURCE_AUDIO_CHANNEL},
+ * {@link #VIBRATION_SOURCE_APPLICATION_PROVIDED}, or system default vibration.
+ */
+ public static final int VIBRATION_SOURCE_DEFAULT = 0;
+
+ /** Specifies that vibration is explicitly disabled for this ringtone. */
+ public static final int VIBRATION_SOURCE_OFF = 1;
+
+ /** The vibration Uri should be used as the source of vibration. */
+ public static final int VIBRATION_SOURCE_URI = 2;
+
+ /**
+ * Specifies that vibration should use the vibration provided by the application. This is
+ * typically the application's own default for the use-case, provided via
+ * {@link Ringtone.Builder#setVibrationEffect}. For notification channels, this is the vibration
+ * effect saved on the notification channel.
+ *
+ * <p>If no vibration is specified by the application, this value behaves if the source was
+ * {@link #VIBRATION_SOURCE_DEFAULT}.
+ */
+ public static final int VIBRATION_SOURCE_APPLICATION_PROVIDED = 3;
+
+ /**
+ * Specifies that vibration should use haptic audio channels from the
+ * sound Uri. If the sound URI doesn't have haptic channels, then reverts to the order specified
+ * by {@link #VIBRATION_SOURCE_DEFAULT}.
+ */
+ // Numeric gap from VIBRATION_SOURCE_APPLICATION_PROVIDED in case we want other common elements.
+ public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10;
+
+ /**
+ * Specifies that vibration should generate haptic audio channels from the
+ * audio tracks of the sound Uri.
+ *
+ * If the sound Uri already has haptic channels, then behaves as though
+ * {@link #VIBRATION_SOURCE_AUDIO_CHANNEL} was specified instead.
+ */
+ public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11;
+
+ /**
+ * Directive for how to vibrate.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "VIBRATION_SOURCE_", value = {
+ VIBRATION_SOURCE_UNKNOWN,
+ VIBRATION_SOURCE_DEFAULT,
+ VIBRATION_SOURCE_OFF,
+ VIBRATION_SOURCE_URI,
+ VIBRATION_SOURCE_APPLICATION_PROVIDED,
+ VIBRATION_SOURCE_AUDIO_CHANNEL,
+ VIBRATION_SOURCE_HAPTIC_GENERATOR,
+ })
+ public @interface VibrationSource {}
+
+ /**
+ * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the sound Uri
+ * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF}.
+ * This behavior is particularly suited to loading values from older settings that may contain
+ * a raw sound Uri or null for silent.
+ *
+ * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
+ */
+ public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1;
+
+ /**
+ * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the vibration
+ * Uri for the returned {@link RingtoneSelection}, with null meaning
+ * {@link #VIBRATION_SOURCE_OFF}.
+ *
+ * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
+ */
+ public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2;
+
+ /**
+ * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as an invalid
+ * value. Null or an invalid values will revert to default behavior correspnoding to
+ * {@link #DEFAULT_SELECTION_URI_STRING}.
+ *
+ * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false,
+ * which include {@code null}.
+ */
+ public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3;
+
+ /**
+ * How to treat values in {@link #fromUri}.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "FROM_URI_", value = {
+ FROM_URI_RINGTONE_SELECTION_OR_SOUND,
+ FROM_URI_RINGTONE_SELECTION_OR_VIBRATION,
+ FROM_URI_RINGTONE_SELECTION_ONLY
+ })
+ public @interface FromUriBehavior {}
+
+ private static final String BASE_RINGTONE_URI = "content://media/ringtone";
+ /**
+ * String representation of a RingtoneSelection Uri that says to use defaults (equivalent
+ * to {@code new RingtoneSelection.Builder().build()}).
+ */
+ public static final String DEFAULT_SELECTION_URI_STRING = BASE_RINGTONE_URI;
+
+ private static final String MEDIA_URI_RINGTONE_PATH = "/ringtone";
+
+ /* Query param keys. */
+ private static final String URI_PARAM_SOUND_URI = "su";
+ private static final String URI_PARAM_SOUND_SOURCE = "ss";
+ private static final String URI_PARAM_VIBRATION_URI = "vu";
+ private static final String URI_PARAM_VIBRATION_SOURCE = "vs";
+
+ /* Common param values */
+ private static final String SOURCE_OFF_STRING = "off";
+
+ /* Vibration source param values. */
+ private static final String VIBRATION_SOURCE_AUDIO_CHANNEL_STRING = "ac";
+ private static final String VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING = "app";
+ private static final String VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING = "hg";
+
+ @Nullable
+ private final Uri mSoundUri;
+ @SoundSource
+ private final int mSoundSource;
+
+ @Nullable
+ private final Uri mVibrationUri;
+ @VibrationSource
+ private final int mVibrationSource;
+
+ private RingtoneSelection(@Nullable Uri soundUri, @SoundSource int soundSource,
+ @Nullable Uri vibrationUri, @VibrationSource int vibrationSource) {
+ // Enforce guarantees on the source values: revert to unset if they depend on something
+ // that's not set.
+ switch (soundSource) {
+ case SOUND_SOURCE_URI:
+ case SOUND_SOURCE_UNKNOWN: // Allow unknown to revert to URI before default.
+ mSoundSource = soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_DEFAULT;
+ break;
+ default:
+ mSoundSource = soundSource;
+ break;
+ }
+ switch (vibrationSource) {
+ case VIBRATION_SOURCE_AUDIO_CHANNEL:
+ case VIBRATION_SOURCE_HAPTIC_GENERATOR:
+ mVibrationSource = soundUri != null ? vibrationSource : VIBRATION_SOURCE_DEFAULT;
+ break;
+ case VIBRATION_SOURCE_URI:
+ case VIBRATION_SOURCE_UNKNOWN: // Allow unknown to revert to URI.
+ mVibrationSource =
+ vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_DEFAULT;
+ break;
+ default:
+ mVibrationSource = vibrationSource;
+ break;
+ }
+ // Clear Uri values if they're un-used by the source.
+ switch (mSoundSource) {
+ case SOUND_SOURCE_OFF:
+ mSoundUri = null;
+ break;
+ default:
+ // Unset case isn't handled here: the defaulting behavior is left to the player.
+ mSoundUri = soundUri;
+ break;
+ }
+ switch (mVibrationSource) {
+ case VIBRATION_SOURCE_OFF:
+ case VIBRATION_SOURCE_APPLICATION_PROVIDED:
+ case VIBRATION_SOURCE_AUDIO_CHANNEL:
+ case VIBRATION_SOURCE_HAPTIC_GENERATOR:
+ mVibrationUri = null;
+ break;
+ default:
+ // Unset case isn't handled here: the defaulting behavior is left to the player.
+ mVibrationUri = vibrationUri;
+ break;
+ }
+ }
+
+ /**
+ * Returns the stored sound behavior.
+ */
+ @SoundSource
+ public int getSoundSource() {
+ return mSoundSource;
+ }
+
+ /**
+ * Returns the sound Uri for this selection. This is guaranteed to be non-null if
+ * {@link #getSoundSource} returns {@link #SOUND_SOURCE_URI}.
+ */
+ @Nullable
+ public Uri getSoundUri() {
+ return mSoundUri;
+ }
+
+ /**
+ * Returns the selected vibration behavior.
+ */
+ @VibrationSource
+ public int getVibrationSource() {
+ return mVibrationSource;
+ }
+
+ /**
+ * Returns the vibration Uri for this selection. This is guaranteed to be non-null if
+ * {@link #getVibrationSource} returns {@link #SOUND_SOURCE_URI}.
+ */
+ @Nullable
+ public Uri getVibrationUri() {
+ return mVibrationUri;
+ }
+
+ /**
+ * Converts the ringtone selection into a Uri-form, suitable for storing as a user preference
+ * or returning as a result.
+ */
+ @NonNull
+ public Uri toUri() {
+ Uri.Builder builder = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(MediaStore.AUTHORITY)
+ .path(MEDIA_URI_RINGTONE_PATH);
+ if (mSoundUri != null) {
+ builder.appendQueryParameter(URI_PARAM_SOUND_URI, mSoundUri.toString());
+ }
+ // Only off is explicit for sound sources
+ String soundSourceStr = soundSourceToString(mSoundSource);
+ if (soundSourceStr != null) {
+ builder.appendQueryParameter(URI_PARAM_SOUND_SOURCE, soundSourceStr);
+ }
+ if (mVibrationUri != null) {
+ builder.appendQueryParameter(URI_PARAM_VIBRATION_URI, mVibrationUri.toString());
+ }
+ String vibrationSourceStr = vibrationSourceToString(mVibrationSource);
+ if (vibrationSourceStr != null) {
+ builder.appendQueryParameter(URI_PARAM_VIBRATION_SOURCE, vibrationSourceStr);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns true if the Uri is an encoded {@link RingtoneSelection}. This method doesn't
+ * validate the parameters of the selection.
+ *
+ * @see #fromUri
+ * @see #toUri
+ */
+ public static boolean isRingtoneSelectionUri(@Nullable Uri uri) {
+ if (uri == null) {
+ return false;
+ }
+ // Any URI content://media/ringtone
+ return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
+ && MediaStore.AUTHORITY.equals(uri.getAuthority())
+ && MEDIA_URI_RINGTONE_PATH.equals(uri.getPath());
+ }
+
+
+
+ /**
+ * Converts a Uri into a RingtoneSelection.
+ *
+ * <p>Null values and Uris that {@link #isRingtoneSelectionUri(Uri)} returns false will be
+ * treated according to the behaviour specified by the {@code unrecognizedValueBehavior}
+ * parameter.
+ *
+ * @param uri The Uri to convert, potentially null.
+ * @param unrecognizedValueBehavior indicates how to treat values for which
+ * {@link #isRingtoneSelectionUri(Uri)} returns false (including null).
+ * @return the RingtoneSelection represented by the given uri.
+ */
+ @NonNull
+ public static RingtoneSelection fromUri(@Nullable Uri uri,
+ @FromUriBehavior int unrecognizedValueBehavior) {
+ if (isRingtoneSelectionUri(uri)) {
+ return parseRingtoneSelectionUri(uri);
+ }
+ RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
+ switch (unrecognizedValueBehavior) {
+ case FROM_URI_RINGTONE_SELECTION_ONLY:
+ // Always return use-defaults for unrecognized ringtone selection Uris.
+ return builder.build();
+ case FROM_URI_RINGTONE_SELECTION_OR_SOUND:
+ if (uri == null) {
+ return builder.setSoundSource(SOUND_SOURCE_OFF).build();
+ } else {
+ return builder.setSoundSource(uri).build();
+ }
+ case FROM_URI_RINGTONE_SELECTION_OR_VIBRATION:
+ if (uri == null) {
+ return builder.setVibrationSource(VIBRATION_SOURCE_OFF).build();
+ } else {
+ return builder.setVibrationSource(uri).build();
+ }
+ default:
+ throw new IllegalArgumentException("Unknown behavior parameter: "
+ + unrecognizedValueBehavior);
+ }
+ }
+
+ /** Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}. */
+ @NonNull
+ private static RingtoneSelection parseRingtoneSelectionUri(@NonNull Uri uri) {
+ RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
+ int soundSource = stringToSoundSource(uri.getQueryParameter(URI_PARAM_SOUND_SOURCE));
+ int vibrationSource = stringToVibrationSource(
+ uri.getQueryParameter(URI_PARAM_VIBRATION_SOURCE));
+ Uri soundUri = getParamAsUri(uri, URI_PARAM_SOUND_URI);
+ Uri vibrationUri = getParamAsUri(uri, URI_PARAM_VIBRATION_URI);
+ if (soundUri != null) {
+ builder.setSoundSource(soundUri);
+ }
+ if (vibrationUri != null) {
+ builder.setVibrationSource(vibrationUri);
+ }
+ // Don't set the source if there's a URI and the source is default, because that will
+ // override the Uri source set above. In effect, we prioritise "explicit" sources over
+ // an implicit Uri source - except for "default", which isn't really explicit.
+ if (soundSource != SOUND_SOURCE_DEFAULT || soundUri == null) {
+ builder.setSoundSource(soundSource);
+ }
+ if (vibrationSource != VIBRATION_SOURCE_DEFAULT || vibrationUri == null) {
+ builder.setVibrationSource(vibrationSource);
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ private static Uri getParamAsUri(@NonNull Uri uri, String param) {
+ // This returns the uri-decoded value, no need to further decode.
+ String value = uri.getQueryParameter(param);
+ if (value == null) {
+ return null;
+ }
+ return Uri.parse(value);
+ }
+
+ /**
+ * Converts the {@link SoundSource} to the uri query param value for it, or null
+ * if the sound source is default, unknown, or implicit (uri).
+ */
+ @Nullable
+ private static String soundSourceToString(@SoundSource int soundSource) {
+ switch (soundSource) {
+ case SOUND_SOURCE_OFF: return SOURCE_OFF_STRING;
+ default: return null;
+ }
+ }
+
+ /**
+ * Returns the sound source int corresponding to the query string value. Returns
+ * {@link #SOUND_SOURCE_UNKNOWN} if the value isn't recognised, and
+ * {@link #SOUND_SOURCE_DEFAULT} if the value is {@code null} (not in the Uri).
+ */
+ @SoundSource
+ private static int stringToSoundSource(@Nullable String soundSource) {
+ if (soundSource == null) {
+ return SOUND_SOURCE_DEFAULT;
+ }
+ switch (soundSource) {
+ case SOURCE_OFF_STRING: return SOUND_SOURCE_OFF;
+ default: return SOUND_SOURCE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Converts the {@code vibrationSource} to the uri query param value for it, or null
+ * if the vibration source is default, unknown, or implicit (uri).
+ */
+ @Nullable
+ private static String vibrationSourceToString(@VibrationSource int vibrationSource) {
+ switch (vibrationSource) {
+ case VIBRATION_SOURCE_OFF: return SOURCE_OFF_STRING;
+ case VIBRATION_SOURCE_AUDIO_CHANNEL: return VIBRATION_SOURCE_AUDIO_CHANNEL_STRING;
+ case VIBRATION_SOURCE_HAPTIC_GENERATOR:
+ return VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING;
+ case VIBRATION_SOURCE_APPLICATION_PROVIDED:
+ return VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING;
+ default: return null;
+ }
+ }
+
+ @VibrationSource
+ private static int stringToVibrationSource(@Nullable String vibrationSource) {
+ if (vibrationSource == null) {
+ return VIBRATION_SOURCE_DEFAULT;
+ }
+ switch (vibrationSource) {
+ case SOURCE_OFF_STRING: return VIBRATION_SOURCE_OFF;
+ case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING: return VIBRATION_SOURCE_AUDIO_CHANNEL;
+ case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING: return VIBRATION_SOURCE_HAPTIC_GENERATOR;
+ case VIBRATION_SOURCE_APPLICATION_PROVIDED_STRING:
+ return VIBRATION_SOURCE_APPLICATION_PROVIDED;
+ default: return VIBRATION_SOURCE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Builder for {@link RingtoneSelection}. In general, this builder will be used by interfaces
+ * allowing the user to configure their selection. Once a selection is stored as a Uri, then
+ * the RingtoneSelection can be loaded directly using {@link RingtoneSelection#fromUri}.
+ */
+ public static final class Builder {
+ private Uri mSoundUri;
+ private Uri mVibrationUri;
+ @SoundSource private int mSoundSource = SOUND_SOURCE_DEFAULT;
+ @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_DEFAULT;
+
+ /**
+ * Creates a new {@link RingtoneSelection} builder. A default ringtone selection has its
+ * sound and vibration source unset, which means they would fall back to system defaults.
+ */
+ public Builder() {}
+
+ /**
+ * Creates a builder initialized with the given ringtone selection.
+ */
+ public Builder(@NonNull RingtoneSelection selection) {
+ requireNonNull(selection);
+ mSoundSource = selection.getSoundSource();
+ mSoundUri = selection.getSoundUri();
+ mVibrationSource = selection.getVibrationSource();
+ mVibrationUri = selection.getVibrationUri();
+ }
+
+ /**
+ * Sets the desired sound source.
+ *
+ * <p>Values other than {@link #SOUND_SOURCE_URI} will clear any previous sound Uri.
+ * For {@link #SOUND_SOURCE_URI}, the {@link #setSoundSource(Uri)} method should be
+ * used instead, as setting it here will have no effect unless the Uri is also set.
+ */
+ @NonNull
+ public Builder setSoundSource(@SoundSource int soundSource) {
+ mSoundSource = soundSource;
+ if (soundSource != SOUND_SOURCE_URI && soundSource != SOUND_SOURCE_UNKNOWN) {
+ // Note that this means the configuration of "silent sound, but use haptic
+ // generator" is currently not supported. Future support could be added by either
+ // using the vibration uri in that case, or by having a special
+ // "setSoundUriForVibrationOnly(Uri)" method that sets sound source to off but
+ // also retains the Uri.
+ mSoundUri = null;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the sound source to {@link #SOUND_SOURCE_URI}, and the sound Uri to the
+ * specified {@link Uri}.
+ */
+ @NonNull
+ public Builder setSoundSource(@NonNull Uri soundUri) {
+ mSoundUri = requireNonNull(soundUri);
+ mSoundSource = SOUND_SOURCE_URI;
+ return this;
+ }
+
+ /**
+ * Sets the vibration source to the specified value.
+ *
+ * <p>Values other than {@link #VIBRATION_SOURCE_URI} will clear any previous vibration Uri.
+ * For {@link #VIBRATION_SOURCE_URI}, the {@link #setVibrationSource(Uri)} method should be
+ * used instead, as setting it here will have no effect unless the Uri is also set.
+ */
+ @NonNull
+ public Builder setVibrationSource(@VibrationSource int vibrationSource) {
+ mVibrationSource = vibrationSource;
+ if (vibrationSource != VIBRATION_SOURCE_URI
+ && vibrationSource != VIBRATION_SOURCE_UNKNOWN) {
+ mVibrationUri = null;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the vibration source to {@link #VIBRATION_SOURCE_URI}, and the vibration Uri to the
+ * specified {@link Uri}.
+ */
+ @NonNull
+ public Builder setVibrationSource(@NonNull Uri vibrationUri) {
+ mVibrationUri = requireNonNull(vibrationUri);
+ mVibrationSource = VIBRATION_SOURCE_URI;
+ return this;
+ }
+
+ /**
+ * Returns the ringtone Uri that was configured.
+ */
+ @NonNull
+ public RingtoneSelection build() {
+ return new RingtoneSelection(mSoundUri, mSoundSource, mVibrationUri, mVibrationSource);
+ }
+ }
+}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index e1af909..0bc5a60 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -100,8 +100,12 @@
boolean volumeAdjustmentForRemoteGroupSessions = Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
- mVolumeHandling = defineVolumeHandling(builder.mVolumeHandling, mSelectedRoutes,
- volumeAdjustmentForRemoteGroupSessions);
+ mVolumeHandling =
+ defineVolumeHandling(
+ mIsSystemSession,
+ builder.mVolumeHandling,
+ mSelectedRoutes,
+ volumeAdjustmentForRemoteGroupSessions);
mControlHints = updateVolumeHandlingInHints(builder.mControlHints, mVolumeHandling);
}
@@ -150,9 +154,14 @@
return controlHints;
}
- private static int defineVolumeHandling(int volumeHandling, List<String> selectedRoutes,
+ private static int defineVolumeHandling(
+ boolean isSystemSession,
+ int volumeHandling,
+ List<String> selectedRoutes,
boolean volumeAdjustmentForRemoteGroupSessions) {
- if (!volumeAdjustmentForRemoteGroupSessions && selectedRoutes.size() > 1) {
+ if (!isSystemSession
+ && !volumeAdjustmentForRemoteGroupSessions
+ && selectedRoutes.size() > 1) {
return MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
}
return volumeHandling;
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 6744359..9b238e1 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -49,7 +49,6 @@
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
@@ -256,19 +255,17 @@
// get orientation
if (MediaFile.isExifMimeType(mimeType)) {
- try (FileInputStream is = new FileInputStream(file)) {
- exif = new ExifInterface(is.getFD());
- switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0)) {
- case ExifInterface.ORIENTATION_ROTATE_90:
- orientation = 90;
- break;
- case ExifInterface.ORIENTATION_ROTATE_180:
- orientation = 180;
- break;
- case ExifInterface.ORIENTATION_ROTATE_270:
- orientation = 270;
- break;
- }
+ exif = new ExifInterface(file);
+ switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0)) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ orientation = 90;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ orientation = 180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ orientation = 270;
+ break;
}
}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 094a33f..ed68d1e 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -455,6 +455,11 @@
if (mRule.getTargetMixType() != AudioMix.MIX_TYPE_PLAYERS) {
throw new IllegalArgumentException("Unsupported device on non-playback mix");
}
+ } else if (mDeviceSystemType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) {
+ if (mRule.getTargetMixType() != AudioMix.MIX_TYPE_PLAYERS) {
+ throw new IllegalArgumentException(
+ "DEVICE_OUT_REMOTE_SUBMIX device is not supported on non-playback mix");
+ }
} else {
if ((mRouteFlags & ROUTE_FLAG_SUPPORTED) == ROUTE_FLAG_RENDER) {
throw new IllegalArgumentException(
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index c1ee74a..3e5de82 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -865,7 +865,7 @@
for (final WeakReference<AudioTrack> weakTrack : mInjectors) {
final AudioTrack track = weakTrack.get();
if (track == null) {
- break;
+ continue;
}
try {
// TODO: add synchronous versions
@@ -876,12 +876,13 @@
// released by the user of the AudioPolicy
}
}
+ mInjectors.clear();
}
if (mCaptors != null) {
for (final WeakReference<AudioRecord> weakRecord : mCaptors) {
final AudioRecord record = weakRecord.get();
if (record == null) {
- break;
+ continue;
}
try {
// TODO: if needed: implement an invalidate method
@@ -891,6 +892,7 @@
// released by the user of the AudioPolicy
}
}
+ mCaptors.clear();
}
}
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index f1cffb6..fb72c7b 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -159,30 +159,42 @@
* @param surface The surface to which the content of the virtual display should be rendered,
* or null if there is none initially.
* @param flags A combination of virtual display flags. See {@link DisplayManager} for the
- * full list of flags.
+ * full list of flags. Note that
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PRESENTATION}
+ * is always enabled. The following flags may be overridden, depending on how
+ * the component with {android.Manifest.permission.MANAGE_MEDIA_PROJECTION}
+ * handles the user's consent:
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR},
+ * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC}.
* @param callback Callback invoked when the virtual display's state changes, or null.
* @param handler The {@link android.os.Handler} on which the callback should be invoked, or
* null if the callback should be invoked on the calling thread's main
* {@link android.os.Looper}.
- * @throws IllegalStateException In the following scenarios, if the target SDK is {@link
- * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U} and up:
+ * @throws IllegalStateException If the target SDK is {@link
+ * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U} and up, and
+ * if no {@link Callback} is registered.
+ * @throws SecurityException In any of the following scenarios:
* <ol>
- * <li>If no {@link Callback} is registered.</li>
- * <li>If {@link MediaProjectionManager#getMediaProjection}
+ * <li>If attempting to create a new virtual display
+ * associated with this MediaProjection instance after it has
+ * been stopped by invoking {@link #stop()}.
+ * <li>If the target SDK is {@link
+ * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U} and up,
+ * and if this instance has already taken a recording through
+ * {@code #createVirtualDisplay}, but {@link #stop()} wasn't
+ * invoked to end the recording.
+ * <li>If the target SDK is {@link
+ * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U} and up,
+ * and if {@link MediaProjectionManager#getMediaProjection}
* was invoked more than once to get this
* {@code MediaProjection} instance.
- * <li>If this instance has already taken a recording through
- * {@code #createVirtualDisplay}.
* </ol>
- * However, if the target SDK is less than
- * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U}, no
- * exception is thrown. In case 1, recording begins even without
- * the callback. In case 2 & 3, recording doesn't begin
- * until the user re-grants consent in the dialog.
- * @throws SecurityException If attempting to create a new virtual display associated with this
- * MediaProjection instance after it has been stopped by invoking
- * {@link #stop()}.
- *
+ * In cases 2 & 3, no exception is thrown if the target SDK is
+ * less than
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE U}.
+ * Instead, recording doesn't begin until the user re-grants
+ * consent in the dialog.
* @see VirtualDisplay
* @see VirtualDisplay.Callback
*/
diff --git a/media/java/android/mtp/OWNERS b/media/java/android/mtp/OWNERS
index 1928ba8..6b5336e 100644
--- a/media/java/android/mtp/OWNERS
+++ b/media/java/android/mtp/OWNERS
@@ -1,6 +1,9 @@
set noparent
-marcone@google.com
+aprasath@google.com
+anothermark@google.com
+kumarashishg@google.com
+sarup@google.com
jsharkey@android.com
jameswei@google.com
rmojumder@google.com
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
index 445672b..96894d1 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -1,5 +1,5 @@
# extra for MTP related files
-per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
+per-file android_mtp_*.cpp=aprasath@google.com,anothermark@google.com,kumarashishg@google.com,sarup@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
# extra for TV related files
per-file android_media_tv_*=hgchen@google.com,quxiangfang@google.com
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
index bbca882..ac8a7f3 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
@@ -24,7 +24,11 @@
import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_AUDIO_SESSION_ID;
import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_UID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
import android.media.AudioFormat;
+import android.media.AudioSystem;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioMixingRule;
import android.media.audiopolicy.AudioPolicyConfig;
@@ -145,6 +149,84 @@
equalsTester.testEquals();
}
+ @Test
+ public void buildRenderToRemoteSubmix_success() {
+ final String deviceAddress = "address";
+ final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
+ .setDevice(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, /*address=*/deviceAddress).build();
+
+ assertEquals(deviceAddress, audioMix.getRegistration());
+ assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
+ assertEquals(AudioMix.ROUTE_FLAG_RENDER, audioMix.getRouteFlags());
+ }
+
+ @Test
+ public void buildLoopbackAndRenderToRemoteSubmix_success() {
+ final String deviceAddress = "address";
+ final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER)
+ .setDevice(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, /*address=*/deviceAddress).build();
+
+ assertEquals(deviceAddress, audioMix.getRegistration());
+ assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
+ assertEquals(AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER, audioMix.getRouteFlags());
+ }
+
+ @Test
+ public void buildRenderToSpeaker_success() {
+ final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
+ .setDevice(AudioSystem.DEVICE_OUT_SPEAKER, /*address=*/"").build();
+
+ assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
+ assertEquals(AudioMix.ROUTE_FLAG_RENDER, audioMix.getRouteFlags());
+ }
+
+ @Test
+ public void buildLoopbackForPlayerMix_success() {
+ final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
+
+ assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
+ assertEquals(AudioMix.ROUTE_FLAG_LOOP_BACK, audioMix.getRouteFlags());
+ }
+
+ @Test
+ public void buildLoopbackWithDevice_throws() {
+ assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
+ new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
+ .setDevice(AudioSystem.DEVICE_OUT_SPEAKER, /*address=*/"").build());
+ }
+
+ @Test
+ public void buildRenderWithoutDevice_throws() {
+ assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
+ new AudioMixingRule.Builder()
+ .setTargetMixRole(MIX_ROLE_PLAYERS)
+ .addMixRule(RULE_MATCH_UID, 42).build())
+ .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER).build());
+ }
+
+
+
private static AudioMix writeToAndFromParcel(AudioMix audioMix) {
AudioPolicyConfig apc = new AudioPolicyConfig(new ArrayList<>(List.of(audioMix)));
Parcel parcel = Parcel.obtain();
diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS
index 1928ba8..6b5336e 100644
--- a/media/tests/MtpTests/OWNERS
+++ b/media/tests/MtpTests/OWNERS
@@ -1,6 +1,9 @@
set noparent
-marcone@google.com
+aprasath@google.com
+anothermark@google.com
+kumarashishg@google.com
+sarup@google.com
jsharkey@android.com
jameswei@google.com
rmojumder@google.com
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index cb74cfc..fd785a4 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -52,6 +52,7 @@
?application/sdp sdp
?application/smil+xml smil
?application/ttml+xml ttml dfxp
+?application/vnd.android.haptics.vibration+xml ahv
?application/vnd.android.ota ota
?application/vnd.apple.mpegurl m3u8
?application/vnd.ms-pki.stl stl
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 1082c0a..6c54f70 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Gee die app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Kies ’n toestel wat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> moet bestuur"</string>
<string name="chooser_title" msgid="2235819929238267637">"Kies ’n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om op te stel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index a625307..d9ddf71 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲደርስ ይፈቀድለት?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"መተግበሪያው <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲደርስ ይፈቀድለት?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የሚያስተዳድረው መሣሪያ ይምረጡ"</string>
<string name="chooser_title" msgid="2235819929238267637">"የሚያዋቅሩት <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index f15d71f..8a6f227 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
- <string name="confirmation_title" msgid="4593465730772390351">"هل تريد السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>؟"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"هل تريد السماح لـ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"الساعة"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"اختيار جهاز ليديره تطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"اختيار \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" لإعداده"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 4dfe368..28a06e6 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> এক্সেছ কৰিবলৈ দিবনে?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> এপ্টোক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> এক্সেছ কৰিবলৈ দিবনে?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>এ পৰিচালনা কৰিবলগীয়া এটা ডিভাইচ বাছনি কৰক"</string>
<string name="chooser_title" msgid="2235819929238267637">"ছেট আপ কৰিবলৈ এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 9fd055c..18ac2ae 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına daxil olmaq icazəsi verilsin?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına daxil olmaq icazəsi verilsin?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tərəfindən idarə ediləcək cihaz seçin"</string>
<string name="chooser_title" msgid="2235819929238267637">"Ayarlamaq üçün <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 9e3b711..b37ab4b9 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite da podesite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index a9ead16..41889fd 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ да прылады <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ да прылады <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберыце прыладу (<xliff:g id="APP_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Выберыце імя <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для наладжвання"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 80b301b..bb53c5c 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Да се разреши ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Да се разреши ли на приложението <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете устройство, което да се управлява от <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, за да го настроите"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index d789ab9..bc0af0bd 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> অ্যাক্সেস করার অনুমতি দেবেন?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> অ্যাক্সেস করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে কি অনুমতি দিতে চান?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ম্যানেজ করা যাবে এমন একটি ডিভাইস বেছে নিন"</string>
<string name="chooser_title" msgid="2235819929238267637">"সেট-আপ করতে কোনও <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 4c7ced2..538ee35 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da postavite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 17c912c..b6f182d 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vols permetre que l\'aplicació <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Tria un dispositiu perquè el gestioni <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> per configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index fe4d1af..b62496d 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zařízení, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete nastavit"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 072a526..df63e6c 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vil du give appen <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vælg en enhed, som skal administreres af <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vælg en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som du vil konfigurere"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 5a6a20d..f487f94 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> auf das Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zugreifen darf?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> auf <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zugreifen darf?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Gerät auswählen, das von <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> verwaltet werden soll"</string>
<string name="chooser_title" msgid="2235819929238267637">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> zum Einrichten auswählen"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index f7689af..1c8ecb7 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ;"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Επιλέξτε μια συσκευή για διαχείριση μέσω της εφαρμογής <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για ρύθμιση"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index 66a547d..ca12145 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Allow the app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 843e479..bd0342d 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Allow the app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index 66a547d..ca12145 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Allow the app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index 66a547d..ca12145 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Allow the app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 05b27b5c..70af915 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Allow the app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choose a device to be managed by <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 41d29bd..cba0b46 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"¿Quieres permitir que la app de <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lo administre"</string>
<string name="chooser_title" msgid="2235819929238267637">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 9681de6..50d8806 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"¿Permitir que la aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Elige un dispositivo para que lo gestione <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Elige el <xliff:g id="PROFILE_NAME">%1$s</xliff:g> que quieras configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index e8c16e6..2eff7eb 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Andke rakendusele <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> juurdepääs seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Kas anda rakendusele <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> juurdepääs seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Valige seade, mida haldab rakendus <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mis seadistada"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 3bcca29..e130074 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> erabiltzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> gailua erabiltzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Aukeratu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioak kudeatu behar duen gailua"</string>
<string name="chooser_title" msgid="2235819929238267637">"Aukeratu konfiguratu nahi duzun <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 2adb4d8..5e78aa5 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود به <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی پیدا کند؟"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"به برنامه <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود به <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی پیدا کند؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"انتخاب دستگاه برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای راهاندازی"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 11831b6..552c473 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Sallitaanko, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn laitteeseen: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Sallitaanko, että soellus (<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>) saa pääsyn laitteeseen: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Valitse laite, jota <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallinnoi"</string>
<string name="chooser_title" msgid="2235819929238267637">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, niin voit suorittaa käyttöönoton"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 80f4f228..753875b 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Autoriser l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choisir un appareil qui sera géré par <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Choisir un appareil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pour le configurer"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 0469470..d3704a0 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Autoriser l\'appli <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Sélectionner l\'appareil qui sera géré par <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Sélectionner votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g> à configurer"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index be232e9..a7aa72d 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda ao dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Queres permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda ao dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolle un dispositivo para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolle o perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) que queiras configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 22b9d39..443fb4b 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"શું <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ઍપને મંજૂરી આપીએ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ ડિવાઇસ પસંદ કરો"</string>
<string name="chooser_title" msgid="2235819929238267637">"સેટઅપ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 82eeecd..494af37 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"क्या <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> को ऐक्सेस करने के लिए <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अनुमति देनी है?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"क्या <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> को ऐक्सेस करने के लिए <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ऐप्लिकेशन को अनुमति देनी है?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> से मैनेज किया जाने वाला डिवाइस चुनें"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप करने के लिए कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index fc1a750..5e175bc 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Želite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Želite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite postaviti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 4f74486..ba480f6 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hozzáférését a következőhöz: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazás számára, hogy hozzáférjen a következőhöz: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazással kezelni kívánt eszköz kiválasztása"</string>
<string name="chooser_title" msgid="2235819929238267637">"Válassza ki a beállítani kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> nevet."</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index c6edd89..9385fd1 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Ընտրեք սարքը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածի միջոցով"</string>
<string name="chooser_title" msgid="2235819929238267637">"Կարգավորելու համար ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 6feff73..c03a5ab 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Izinkan aplikasi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih perangkat untuk dikelola oleh <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disiapkan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 283d0e6..fc9f5a1 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Veita forritinu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Veldu tæki sem <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> á að stjórna"</string>
<string name="chooser_title" msgid="2235819929238267637">"Veldu <xliff:g id="PROFILE_NAME">%1$s</xliff:g> til að setja upp"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index dfbd2f5..be431b6 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -16,8 +16,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="app_label" msgid="4470785958457506021">"Gestione dispositivi associati"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Scegli un dispositivo che sia gestito da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da configurare"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 13e514c..8982660 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"לאשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&g; לגשת אל <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"לאפשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת אל <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"בחירה של מכשיר לניהול באמצעות <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> להגדרה"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 4ddef24..186944a 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャー"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> へのアクセスを許可しますか?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> アプリに <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> へのアクセスを許可しますか?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> の管理対象となるデバイスの選択"</string>
<string name="chooser_title" msgid="2235819929238267637">"設定する<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 995b4e7..a7c6042 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"მიანიჭებთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> მოწყობილობაზე წვდომას?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"ნებას რთავთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს, წვდომა ჰქონდეს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> მოწყობილობაზე?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"აირჩიეთ მოწყობილობა, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპმა"</string>
<string name="chooser_title" msgid="2235819929238267637">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> დასაყენებლად"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 0330d96..5c6d24a 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын пайдалануға рұқсат беру керек пе?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? құрылғысына кіруге рұқсат беріңіз"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> арқылы басқарылатын құрылғыны таңдаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Реттеу үшін <xliff:g id="PROFILE_NAME">%1$s</xliff:g> таңдаңыз"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index e9ca811..c734cb6 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"កម្មវិធីគ្រប់គ្រងឧបករណ៍ដៃគូ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"អនុញ្ញាតឱ្យកម្មវិធី <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"ជ្រើសរើសឧបករណ៍ ដើម្បីដាក់ក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីរៀបចំ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 0643336..5f04cd3 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ ಸಾಧನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ಸೆಟಪ್ ಮಾಡಲು <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆರಿಸಿ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 7d277c9..e4c56b2 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 액세스하도록 허용하시겠습니까?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>앱에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 액세스하도록 허용하시겠습니까?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 관리할 기기 선택"</string>
<string name="chooser_title" msgid="2235819929238267637">"설정할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 선택"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index c5f3d21..d33cced 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүнө кирүүгө уруксат бересизби?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүнө кирүүгө уруксат бересизби?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> аркылуу башкарыла турган түзмөктү тандаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Тууралоо үчүн <xliff:g id="PROFILE_NAME">%1$s</xliff:g> тандаңыз"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index bdb5fd9..0072e4b 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"ອະນຸຍາດໃຫ້ແອັບ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"ເລືອກອຸປະກອນທີ່ຈະໃຫ້ມີການຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ທີ່ຈະຕັ້ງຄ່າ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index a32d5b4..65a266d 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Leisti programai <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Įrenginio, kuris bus valdomas naudojant programą <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, pasirinkimas"</string>
<string name="chooser_title" msgid="2235819929238267637">"Norimo nustatyti <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pasirinkimas"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 94d573e..1d29edc 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt lietotnei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izvēlieties ierīci, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Jāizvēlas <xliff:g id="PROFILE_NAME">%1$s</xliff:g> iestatīšanai"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 249b3c9..e72e960 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Ќе дозволите <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Дозволувате апликацијата <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Изберете уред со којшто ќе управува <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> за поставување"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index a408b65..1703742 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു ഉപകരണം തിരഞ്ഞെടുക്കുക"</string>
<string name="chooser_title" msgid="2235819929238267637">"സജ്ജീകരിക്കാൻ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 4464c05..613c9aa 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-д <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д хандахыг зөвшөөрөх үү?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-д <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> аппыг хандахыг зөвшөөрөх үү?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-н удирдах төхөөрөмжийг сонгоно уу"</string>
<string name="chooser_title" msgid="2235819929238267637">"Тохируулахын тулд <xliff:g id="PROFILE_NAME">%1$s</xliff:g> сонгоно уу"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index ee699d5..50ab307 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> अॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> अॅपला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> अॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी डिव्हाइस निवडा"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 04837ff..ef110b6 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Benarkan apl <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pilih peranti untuk diurus oleh <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk disediakan"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 9c7048b..57f2e23 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? သုံးခွင့်ပြုခြင်း"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို သုံးရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အက်ပ်ကို ခွင့်ပြုမလား။"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> က စီမံခန့်ခွဲရန် စက်တစ်ခုကို ရွေးပါ"</string>
<string name="chooser_title" msgid="2235819929238267637">"စနစ်ထည့်သွင်းရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးပါ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 8ecaeba..083ec99 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vil du gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-appen tilgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Velg en enhet som skal administreres av <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal konfigureres"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index a5ca130..7a1df5f 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> प्रयोग गर्ने अनुमति दिने हो?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> एपलाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> प्रयोग गर्ने अनुमति दिने हो?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"आफूले <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको डिभाइस चयन गर्नुहोस्"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप गर्नका लागि <xliff:g id="PROFILE_NAME">%1$s</xliff:g> छनौट गर्नुहोस्"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 8c29b9f..71d14e7 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"De app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Een apparaat kiezen om te beheren met <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om in te stellen"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index f7d814c..a058374 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ଆପକୁ ଅନୁମତି ଦେବେ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ ଡିଭାଇସ ବାଛନ୍ତୁ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ସେଟ ଅପ କରିବାକୁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ବାଛନ୍ତୁ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index 3169ded..984ec48 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਐਪ ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ ਕੋਈ ਡੀਵਾਈਸ ਚੁਣੋ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 8daa15b..7ca172e 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Zezwolić na dostęp aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do tego urządzenia (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Zezwolić aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do urządzenia <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Wybierz urządzenie, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, aby go skonfigurować"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index c0224da..26647c8 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index cc5f81b..ba60f56 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerido pela app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um perfil de <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index c0224da..26647c8 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Escolha um dispositivo para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para configurar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 203cda4..84182e8 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Alege un dispozitiv pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Alege un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> de configurat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 1644f0d2..911bddc 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Предоставить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ к устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Предоставить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ к устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберите устройство, которым будет управлять приложение <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Выберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для настройки"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 57a6bce..daa2058 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> වෙත ප්රවේශ වීමට ඉඩ දෙන්න ද?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> යෙදුමට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> වෙත ප්රවේශ වීමට ඉඩ දෙන්න ද?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> විසින් කළමනා කරනු ලැබීමට උපාංගයක් තෝරන්න"</string>
<string name="chooser_title" msgid="2235819929238267637">"සැකසීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 8279e1e..929b56c 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zariadenie, ktoré bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý nastavíte"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 85d657d..b1b1e91 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izbira naprave, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Izberite profil naprave »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>« za nastavitev"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index f7144db..037a707 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"T\'i lejohet <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> qasja te <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"T\'i lejohet aplikacionit <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> qasja te <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Zgjidh një pajisje që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Zgjidh një <xliff:g id="PROFILE_NAME">%1$s</xliff:g> për konfigurimin"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 0b634c5..3817d58 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Дозволите да апликација <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Одаберите уређај којим ће управљати апликација <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> који желите да подесите"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index b442412..f3be3be 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Vill du tillåta att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får åtkomst till <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vill du tillåta att appen <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får åtkomst till <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Välj en enhet för hantering av <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för konfigurering"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 92932c7..7b94239 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Chagua kifaa cha kudhibitiwa na <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili uweke mipangilio"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index c3fef61..c1b8352 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்தை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்தை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸால் நிர்வகிக்கப்பட வேண்டிய சாதனத்தைத் தேர்வுசெய்யுங்கள்"</string>
<string name="chooser_title" msgid="2235819929238267637">"அமைக்க <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்வுசெய்யவும்"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 95a5ace..52316cd 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించాలా?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడే పరికరాన్ని ఎంచుకోండి"</string>
<string name="chooser_title" msgid="2235819929238267637">"సెటప్ చేయడానికి <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index dc9e242..cb01f2d 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึง <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"อนุญาตให้แอป <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึง <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ใช่ไหม"</string>
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"เลือกอุปกรณ์ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะตั้งค่า"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index f50da1b..43d5996 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Payagan ang app na <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pumili ng device na papamahalaan ng <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para mag-set up"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index fbe9b02..1e8e842 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -17,13 +17,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına erişmesi için <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına izin verin"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına erişmesi için <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına izin verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tarafından yönetilecek bir cihaz seçin"</string>
<string name="chooser_title" msgid="2235819929238267637">"Ayarlamak için bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
<string name="summary_watch" msgid="7962014927042971830">"Bu uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine ve <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda aşağıdaki izinlere erişmesine izin verilir"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazını yönetmesi için izin verilsin mi?"</string>
- <string name="profile_name_glasses" msgid="3506504967216601277">"cihaz"</string>
+ <string name="profile_name_glasses" msgid="3506504967216601277">"Cihaz"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Bu uygulamanın <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda şu izinlere erişmesine izin verilecek:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index aa7438b..39a2b1b 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Надати додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до інформації на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до інформації на пристрої <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Виберіть пристрій, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для налаштування"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 9cf41cf..ce44941 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> تک رسائی کی اجازت دیں؟"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"ایپ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> تک رسائی کی اجازت دیں؟"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کے ذریعے منتخب کیے جانے کیلئے آلہ منتخب کریں"</string>
<string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 42dcd72..82b6937 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> boshqaradigan qurilmani tanlang"</string>
<string name="chooser_title" msgid="2235819929238267637">"Sozlash uchun <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilini tanlang"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 51f69b2..951f429 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Trình quản lý thiết bị đồng hành"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Cho phép ứng dụng <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Chọn một thiết bị sẽ do <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý"</string>
<string name="chooser_title" msgid="2235819929238267637">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> để thiết lập"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 578302b..5edf9c0 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>访问<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"允许应用<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>访问<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"选择要由<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理的设备"</string>
<string name="chooser_title" msgid="2235819929238267637">"选择 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 进行设置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 22694eb..0878c23 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 管理的裝置"</string>
<string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index a8151de..4f50ef5 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>應用程式存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理的裝置"</string>
<string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index d9b5c52..7fb5ece 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
- <string name="confirmation_title" msgid="4593465730772390351">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Vumela i-app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Khetha idivayisi engaphathwa nge-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="chooser_title" msgid="2235819929238267637">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ukusetha"</string>
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
index e88410c..8699f59 100644
--- a/packages/EasterEgg/Android.bp
+++ b/packages/EasterEgg/Android.bp
@@ -26,7 +26,10 @@
android_app {
// the build system in pi-dev can't quite handle R.java in kt
// so we will have a mix of java and kotlin files
- srcs: ["src/**/*.java", "src/**/*.kt"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
resource_dirs: ["res"],
@@ -36,17 +39,34 @@
certificate: "platform",
optimize: {
+ enabled: true,
+ optimize: true,
+ shrink: true,
+ shrink_resources: true,
+ proguard_compatibility: false,
proguard_flags_files: ["proguard.flags"],
},
- static_libs: [
- "androidx.core_core",
- "androidx.recyclerview_recyclerview",
+ static_libs: [
+ "androidx.core_core",
"androidx.annotation_annotation",
- "kotlinx-coroutines-android",
- "kotlinx-coroutines-core",
- //"kotlinx-coroutines-reactive",
- ],
+ "androidx.recyclerview_recyclerview",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
+
+ "androidx.core_core-ktx",
+ "androidx.lifecycle_lifecycle-runtime-ktx",
+ "androidx.activity_activity-compose",
+ "androidx.compose.ui_ui",
+ "androidx.compose.ui_ui-util",
+ "androidx.compose.ui_ui-tooling-preview",
+ "androidx.compose.material_material",
+ "androidx.window_window",
+
+ "androidx.compose.runtime_runtime",
+ "androidx.activity_activity-compose",
+ "androidx.compose.ui_ui",
+ ],
manifest: "AndroidManifest.xml",
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index cc7bb4a..d1db237 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,4 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.egg"
android:versionCode="12"
@@ -18,8 +33,27 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
- android:icon="@drawable/icon"
+ android:icon="@drawable/android14_patch_adaptive"
android:label="@string/app_name">
+
+ <!-- Android U easter egg -->
+
+ <activity
+ android:name=".landroid.MainActivity"
+ android:exported="true"
+ android:label="@string/u_egg_name"
+ android:icon="@drawable/android14_patch_adaptive"
+ android:configChanges="orientation|screenLayout|screenSize|density"
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
+
+ <!-- Android Q easter egg -->
<activity
android:name=".quares.QuaresActivity"
android:exported="true"
@@ -69,7 +103,7 @@
android:exported="true"
android:showOnLockScreen="true"
android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" />
- <!-- Used to enable easter egg -->
+ <!-- Used to enable easter egg components for earlier easter eggs. -->
<activity
android:name=".ComponentActivationActivity"
android:excludeFromRecents="true"
@@ -79,7 +113,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
</activity>
diff --git a/packages/EasterEgg/res/drawable/android14_patch_adaptive.xml b/packages/EasterEgg/res/drawable/android14_patch_adaptive.xml
new file mode 100644
index 0000000..423e351
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android14_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android14_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android14_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android14_patch_monochrome"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/android14_patch_adaptive_background.xml b/packages/EasterEgg/res/drawable/android14_patch_adaptive_background.xml
new file mode 100644
index 0000000..c31aa7b
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android14_patch_adaptive_background.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M0,0 L108,0 L108,108 L0,108 z"
+ android:fillColor="#FF073042"/>
+ <path
+ android:pathData="M44.51,43.32L44.86,42.27C47.04,54.48 52.81,86.71 52.81,50.14C52.81,49.99 52.92,49.86 53.06,49.86H55.04C55.18,49.86 55.3,49.98 55.3,50.14C55.27,114.18 44.51,43.32 44.51,43.32Z"
+ android:fillColor="#3DDC84"/>
+ <path
+ android:name="planetary head"
+ android:pathData="M38.81,42.23L33.63,51.21C33.33,51.72 33.51,52.38 34.02,52.68C34.54,52.98 35.2,52.8 35.49,52.28L40.74,43.2C49.22,47 58.92,47 67.4,43.2L72.65,52.28C72.96,52.79 73.62,52.96 74.13,52.65C74.62,52.35 74.79,51.71 74.51,51.21L69.33,42.23C78.23,37.39 84.32,28.38 85.21,17.74H22.93C23.82,28.38 29.91,37.39 38.81,42.23Z"
+ android:fillColor="#ffffff"/>
+ <!-- yes it's an easter egg in a vector drawable -->
+ <path
+ android:name="planetary body"
+ android:pathData="M22.9,0 L85.1,0 L85.1,15.5 L22.9,15.5 z"
+ android:fillColor="#ffffff" />
+ <path
+ android:pathData="M54.96,43.32H53.1C52.92,43.32 52.77,43.47 52.77,43.65V48.04C52.77,48.22 52.92,48.37 53.1,48.37H54.96C55.15,48.37 55.3,48.22 55.3,48.04V43.65C55.3,43.47 55.15,43.32 54.96,43.32Z"
+ android:fillColor="#3DDC84"/>
+ <path
+ android:pathData="M54.99,40.61H53.08C52.91,40.61 52.77,40.75 52.77,40.92V41.56C52.77,41.73 52.91,41.87 53.08,41.87H54.99C55.16,41.87 55.3,41.73 55.3,41.56V40.92C55.3,40.75 55.16,40.61 54.99,40.61Z"
+ android:fillColor="#3DDC84"/>
+ <path
+ android:pathData="M41.49,47.88H40.86V48.51H41.49V47.88Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M44.13,57.08H43.5V57.71H44.13V57.08Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72.29,66.76H71.66V67.39H72.29V66.76Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M59.31,53.41H58.68V54.04H59.31V53.41Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.47,48.19H63.84V48.83H64.47V48.19Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M60.58,59.09H59.95V59.72H60.58V59.09Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M66.95,56.7H65.69V57.97H66.95V56.7Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M44.13,60.71H43.5V61.34H44.13V60.71Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M49.66,51.33H48.4V52.6H49.66V51.33Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M57.78,63.83H56.52V65.09H57.78V63.83Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M61.1,68.57H59.83V69.83H61.1V68.57Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M40.43,53.73H39.16V54.99H40.43V53.73Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M74.47,44H73.21V45.26H74.47V44Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M36.8,64.58H35.54V65.84H36.8V64.58Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android14_patch_adaptive_foreground.xml b/packages/EasterEgg/res/drawable/android14_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..391d515
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android14_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M54.03,33.03C52.99,33.03 52.14,33.86 52.14,34.87V37.14C52.14,37.34 52.3,37.5 52.5,37.5C52.69,37.5 52.85,37.34 52.85,37.14V36.53C52.85,36.14 53.17,35.82 53.56,35.82H54.51C54.9,35.82 55.22,36.14 55.22,36.53V37.14C55.22,37.34 55.38,37.5 55.57,37.5C55.77,37.5 55.93,37.34 55.93,37.14V34.87C55.93,33.86 55.08,33.03 54.03,33.03H54.03Z"
+ android:fillColor="#3DDC84"/>
+ <path
+ android:pathData="M108,0H0V108H108V0ZM54,80.67C68.73,80.67 80.67,68.73 80.67,54C80.67,39.27 68.73,27.33 54,27.33C39.27,27.33 27.33,39.27 27.33,54C27.33,68.73 39.27,80.67 54,80.67Z"
+ android:fillColor="#F86734"
+ android:fillType="evenOdd"/>
+ <group>
+ <!-- the text doesn't look great everywhere but you can remove the clip to try it out. -->
+ <clip-path />
+ <path
+ android:pathData="M28.58,32.18L29.18,31.5L33.82,33.02L33.12,33.81L32.15,33.48L30.92,34.87L31.37,35.8L30.68,36.58L28.58,32.18L28.58,32.18ZM31.25,33.18L29.87,32.71L30.51,34.02L31.25,33.18V33.18Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M38,29.76L34.61,28.79L36.23,31.04L35.42,31.62L32.8,27.99L33.5,27.48L36.88,28.45L35.26,26.21L36.08,25.62L38.7,29.25L38,29.76Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39.23,23.87L40.63,23.27C41.79,22.77 43.13,23.28 43.62,24.43C44.11,25.57 43.56,26.89 42.4,27.39L40.99,27.99L39.23,23.87ZM42.03,26.54C42.73,26.24 42.96,25.49 42.68,24.83C42.4,24.17 41.69,23.82 41,24.11L40.51,24.32L41.55,26.75L42.03,26.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M45.91,21.43L47.64,21.09C48.47,20.93 49.12,21.41 49.27,22.15C49.38,22.72 49.15,23.14 48.63,23.45L50.57,25.08L49.39,25.31L47.57,23.79L47.41,23.82L47.76,25.63L46.78,25.83L45.91,21.43H45.91ZM47.87,22.86C48.16,22.8 48.34,22.59 48.29,22.34C48.24,22.07 48,21.96 47.71,22.02L47.07,22.14L47.24,22.98L47.87,22.86Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M52.17,22.69C52.19,21.41 53.24,20.39 54.52,20.41C55.8,20.43 56.82,21.49 56.8,22.76C56.78,24.04 55.72,25.06 54.45,25.04C53.17,25.02 52.15,23.96 52.17,22.69ZM55.79,22.75C55.8,22.02 55.23,21.39 54.51,21.38C53.78,21.37 53.19,21.98 53.18,22.7C53.17,23.43 53.73,24.06 54.47,24.07C55.19,24.08 55.78,23.47 55.79,22.75H55.79Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M60,21.01L60.98,21.2L60.12,25.6L59.14,25.41L60,21.01Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.3,22.03L65.73,22.58C66.91,23.03 67.51,24.32 67.07,25.49C66.62,26.65 65.31,27.22 64.13,26.77L62.71,26.22L64.3,22.03L64.3,22.03ZM64.46,25.9C65.17,26.17 65.86,25.8 66.12,25.12C66.37,24.45 66.11,23.71 65.4,23.44L64.91,23.25L63.97,25.72L64.46,25.9Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M73.59,27.94L72.94,27.44L73.51,26.69L74.92,27.77L72.2,31.34L71.45,30.76L73.59,27.94Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76.18,33.75L74.69,32.14L75.25,31.62L78.81,31.42L79.4,32.05L77.47,33.85L77.86,34.27L77.22,34.86L76.83,34.44L76.12,35.11L75.47,34.41L76.18,33.75ZM77.72,32.31L76.12,32.4L76.82,33.15L77.72,32.31Z"
+ android:fillColor="#ffffff"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android14_patch_monochrome.xml b/packages/EasterEgg/res/drawable/android14_patch_monochrome.xml
new file mode 100644
index 0000000..beef85c
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android14_patch_monochrome.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <clip-path
+ android:pathData="M0,0h108v108h-108z"/>
+ <group>
+ <clip-path
+ android:pathData="M22,22h64v64h-64z"/>
+ <path
+ android:pathData="M54,78C67.25,78 78,67.25 78,54C78,40.75 67.25,30 54,30C40.75,30 30,40.75 30,54C30,67.25 40.75,78 54,78Z"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"/>
+ <group>
+ <clip-path
+ android:pathData="M77.5,54C77.5,66.98 66.98,77.5 54,77.5C41.02,77.5 30.5,66.98 30.5,54C30.5,41.02 41.02,30.5 54,30.5C66.98,30.5 77.5,41.02 77.5,54Z"/>
+ <path
+ android:pathData="M61.5,46.06C56.7,47.89 51.4,47.89 46.61,46.06L44.04,50.51C43.49,51.46 42.28,51.79 41.33,51.24C40.39,50.69 40.06,49.48 40.61,48.53L43.06,44.28C37.97,41.03 34.54,35.56 34,29.19L33.88,27.74H74.22L74.1,29.19C73.57,35.56 70.14,41.03 65.04,44.28L67.51,48.56C68.03,49.49 67.71,50.66 66.8,51.21C65.87,51.77 64.65,51.47 64.08,50.54L64.07,50.51L61.5,46.06Z"
+ android:fillColor="#000000"/>
+ </group>
+ <path
+ android:pathData="M51.33,67.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M48.67,62h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M56.67,70h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M56.67,62h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M67.33,62h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M59.33,51.33h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M62,59.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M70,54h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M35.33,56.67h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M35.33,48.67h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M40.67,59.33h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M46,51.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M43.33,67.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M54,54h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ </group>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/values/landroid_strings.xml b/packages/EasterEgg/res/values/landroid_strings.xml
new file mode 100644
index 0000000..1394f2f
--- /dev/null
+++ b/packages/EasterEgg/res/values/landroid_strings.xml
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="u_egg_name" translatable="false">Android 14 Easter Egg</string>
+
+ <string-array name="planet_descriptors" translatable="false">
+ <item>earthy</item>
+ <item>swamp</item>
+ <item>frozen</item>
+ <item>grassy</item>
+ <item>arid</item>
+ <item>crowded</item>
+ <item>ancient</item>
+ <item>lively</item>
+ <item>homey</item>
+ <item>modern</item>
+ <item>boring</item>
+ <item>compact</item>
+ <item>expensive</item>
+ <item>polluted</item>
+ <item>rusty</item>
+ <item>sandy</item>
+ <item>undulating</item>
+ <item>verdant</item>
+ <item>tessellated</item>
+ <item>hollow</item>
+ <item>scalding</item>
+ <item>hemispherical</item>
+ <item>oblong</item>
+ <item>oblate</item>
+ <item>vacuum</item>
+ <item>high-pressure</item>
+ <item>low-pressure</item>
+ <item>plastic</item>
+ <item>metallic</item>
+ <item>burned-out</item>
+ <item>bucolic</item>
+ </string-array>
+
+ <string-array name="life_descriptors" translatable="false">
+ <item>aggressive</item>
+ <item>passive-aggressive</item>
+ <item>shy</item>
+ <item>timid</item>
+ <item>nasty</item>
+ <item>brutish</item>
+ <item>short</item>
+ <item>absent</item>
+ <item>teen-aged</item>
+ <item>confused</item>
+ <item>transparent</item>
+ <item>cubic</item>
+ <item>quadratic</item>
+ <item>higher-order</item>
+ <item>huge</item>
+ <item>tall</item>
+ <item>wary</item>
+ <item>loud</item>
+ <item>yodeling</item>
+ <item>purring</item>
+ <item>slender</item>
+ <item>cats</item>
+ <item>adorable</item>
+ <item>eclectic</item>
+ <item>electric</item>
+ <item>microscopic</item>
+ <item>trunkless</item>
+ <item>myriad</item>
+ <item>cantankerous</item>
+ <item>gargantuan</item>
+ <item>contagious</item>
+ <item>fungal</item>
+ <item>cattywampus</item>
+ <item>spatchcocked</item>
+ <item>rotisserie</item>
+ <item>farm-to-table</item>
+ <item>organic</item>
+ <item>synthetic</item>
+ <item>unfocused</item>
+ <item>focused</item>
+ <item>capitalist</item>
+ <item>communal</item>
+ <item>bossy</item>
+ <item>malicious</item>
+ <item>compliant</item>
+ <item>psychic</item>
+ <item>oblivious</item>
+ <item>passive</item>
+ <item>bonsai</item>
+ </string-array>
+
+ <string-array name="any_descriptors" translatable="false">
+ <item>silly</item>
+ <item>dangerous</item>
+ <item>vast</item>
+ <item>invisible</item>
+ <item>superfluous</item>
+ <item>superconducting</item>
+ <item>superior</item>
+ <item>alien</item>
+ <item>phantom</item>
+ <item>friendly</item>
+ <item>peaceful</item>
+ <item>lonely</item>
+ <item>uncomfortable</item>
+ <item>charming</item>
+ <item>fractal</item>
+ <item>imaginary</item>
+ <item>forgotten</item>
+ <item>tardy</item>
+ <item>gassy</item>
+ <item>fungible</item>
+ <item>bespoke</item>
+ <item>artisanal</item>
+ <item>exceptional</item>
+ <item>puffy</item>
+ <item>rusty</item>
+ <item>fresh</item>
+ <item>crusty</item>
+ <item>glossy</item>
+ <item>lovely</item>
+ <item>processed</item>
+ <item>macabre</item>
+ <item>reticulated</item>
+ <item>shocking</item>
+ <item>void</item>
+ <item>undefined</item>
+ <item>gothic</item>
+ <item>beige</item>
+ <item>mid</item>
+ <item>milquetoast</item>
+ <item>melancholy</item>
+ <item>unnerving</item>
+ <item>cheery</item>
+ <item>vibrant</item>
+ <item>heliotrope</item>
+ <item>psychedelic</item>
+ <item>nondescript</item>
+ <item>indescribable</item>
+ <item>tubular</item>
+ <item>toroidal</item>
+ <item>voxellated</item>
+ <item>low-poly</item>
+ <item>low-carb</item>
+ <item>100% cotton</item>
+ <item>synthetic</item>
+ <item>boot-cut</item>
+ <item>bell-bottom</item>
+ <item>bumpy</item>
+ <item>fluffy</item>
+ <item>sous-vide</item>
+ <item>tepid</item>
+ <item>upcycled</item>
+ <item>sous-vide</item>
+ <item>bedazzled</item>
+ <item>ancient</item>
+ <item>inexplicable</item>
+ <item>sparkling</item>
+ <item>still</item>
+ <item>lemon-scented</item>
+ <item>eccentric</item>
+ <item>tilted</item>
+ <item>pungent</item>
+ <item>pine-scented</item>
+ <item>corduroy</item>
+ <item>overengineered</item>
+ <item>bioengineered</item>
+ <item>impossible</item>
+ </string-array>
+
+ <string-array name="constellations" translatable="false">
+ <item>Aries</item>
+ <item>Taurus</item>
+ <item>Gemini</item>
+ <item>Cancer</item>
+ <item>Leo</item>
+ <item>Virgo</item>
+ <item>Libra</item>
+ <item>Scorpio</item>
+ <item>Sagittarius</item>
+ <item>Capricorn</item>
+ <item>Aquarius</item>
+ <item>Pisces</item>
+ <item>Andromeda</item>
+ <item>Cygnus</item>
+ <item>Draco</item>
+ <item>Alcor</item>
+ <item>Calamari</item>
+ <item>Cuckoo</item>
+ <item>Neko</item>
+ <item>Monoceros</item>
+ <item>Norma</item>
+ <item>Abnorma</item>
+ <item>Morel</item>
+ <item>Redlands</item>
+ <item>Cupcake</item>
+ <item>Donut</item>
+ <item>Eclair</item>
+ <item>Froyo</item>
+ <item>Gingerbread</item>
+ <item>Honeycomb</item>
+ <item>Icecreamsandwich</item>
+ <item>Jellybean</item>
+ <item>Kitkat</item>
+ <item>Lollipop</item>
+ <item>Marshmallow</item>
+ <item>Nougat</item>
+ <item>Oreo</item>
+ <item>Pie</item>
+ <item>Quincetart</item>
+ <item>Redvelvetcake</item>
+ <item>Snowcone</item>
+ <item>Tiramisu</item>
+ <item>Upsidedowncake</item>
+ <item>Vanillaicecream</item>
+ <item>Android</item>
+ <item>Binder</item>
+ <item>Campanile</item>
+ <item>Dread</item>
+ </string-array>
+
+ <!-- prob: 5% -->
+ <string-array name="constellations_rare" translatable="false">
+ <item>Jandycane</item>
+ <item>Zombiegingerbread</item>
+ <item>Astro</item>
+ <item>Bender</item>
+ <item>Flan</item>
+ <item>Untitled-1</item>
+ <item>Expedit</item>
+ <item>Petit Four</item>
+ <item>Worcester</item>
+ <item>Xylophone</item>
+ <item>Yellowpeep</item>
+ <item>Zebraball</item>
+ <item>Hutton</item>
+ <item>Klang</item>
+ <item>Frogblast</item>
+ <item>Exo</item>
+ <item>Keylimepie</item>
+ <item>Nat</item>
+ <item>Nrp</item>
+ </string-array>
+
+ <!-- prob: 75% -->
+ <string-array name="star_suffixes" translatable="false">
+ <item>Alpha</item>
+ <item>Beta</item>
+ <item>Gamma</item>
+ <item>Delta</item>
+ <item>Epsilon</item>
+ <item>Zeta</item>
+ <item>Eta</item>
+ <item>Theta</item>
+ <item>Iota</item>
+ <item>Kappa</item>
+ <item>Lambda</item>
+ <item>Mu</item>
+ <item>Nu</item>
+ <item>Xi</item>
+ <item>Omicron</item>
+ <item>Pi</item>
+ <item>Rho</item>
+ <item>Sigma</item>
+ <item>Tau</item>
+ <item>Upsilon</item>
+ <item>Phi</item>
+ <item>Chi</item>
+ <item>Psi</item>
+ <item>Omega</item>
+
+ <item>Prime</item>
+ <item>Secundo</item>
+ <item>Major</item>
+ <item>Minor</item>
+ <item>Diminished</item>
+ <item>Augmented</item>
+ <item>Ultima</item>
+ <item>Penultima</item>
+ <item>Mid</item>
+
+ <item>Proxima</item>
+ <item>Novis</item>
+
+ <item>Plus</item>
+ </string-array>
+
+ <!-- prob: 5% -->
+ <!-- more than one can be appended, with very low prob -->
+ <string-array name="star_suffixes_rare" translatable="false">
+ <item>Serif</item>
+ <item>Sans</item>
+ <item>Oblique</item>
+ <item>Grotesque</item>
+ <item>Handtooled</item>
+ <item>III “Trey”</item>
+ <item>Alfredo</item>
+ <item>2.0</item>
+ <item>(Final)</item>
+ <item>(Final (Final))</item>
+ <item>(Draft)</item>
+ <item>Con Carne</item>
+ </string-array>
+
+ <string-array name="planet_types" translatable="false">
+ <item>planet</item>
+ <item>planetoid</item>
+ <item>moon</item>
+ <item>moonlet</item>
+ <item>centaur</item>
+ <item>asteroid</item>
+ <item>space garbage</item>
+ <item>detritus</item>
+ <item>satellite</item>
+ <item>core</item>
+ <item>giant</item>
+ <item>body</item>
+ <item>slab</item>
+ <item>rock</item>
+ <item>husk</item>
+ <item>planemo</item>
+ <item>object</item>
+ <item>planetesimal</item>
+ <item>exoplanet</item>
+ <item>ploonet</item>
+ </string-array>
+
+ <string-array name="atmo_descriptors" translatable="false">
+ <item>toxic</item>
+ <item>breathable</item>
+ <item>radioactive</item>
+ <item>clear</item>
+ <item>calm</item>
+ <item>peaceful</item>
+ <item>vacuum</item>
+ <item>stormy</item>
+ <item>freezing</item>
+ <item>burning</item>
+ <item>humid</item>
+ <item>tropical</item>
+ <item>cloudy</item>
+ <item>obscured</item>
+ <item>damp</item>
+ <item>dank</item>
+ <item>clammy</item>
+ <item>frozen</item>
+ <item>contaminated</item>
+ <item>temperate</item>
+ <item>moist</item>
+ <item>minty</item>
+ <item>relaxed</item>
+ <item>skunky</item>
+ <item>breezy</item>
+ <item>soup </item>
+ </string-array>
+
+</resources>
diff --git a/packages/EasterEgg/res/values/q_puzzles.xml b/packages/EasterEgg/res/values/q_puzzles.xml
index 3c9ac0b..bff99d5 100644
--- a/packages/EasterEgg/res/values/q_puzzles.xml
+++ b/packages/EasterEgg/res/values/q_puzzles.xml
@@ -44,7 +44,6 @@
<item>android:drawable/ic_audio_alarm</item>
<item>android:drawable/ic_audio_alarm_mute</item>
- <item>android:drawable/ic_bluetooth_share_icon</item>
<item>android:drawable/ic_bt_headphones_a2dp</item>
<item>android:drawable/ic_bt_headset_hfp</item>
<item>android:drawable/ic_bt_hearing_aid</item>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 743947a..79957df 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android S Easter Egg</string>
+ <string name="app_name" translatable="false">Android Easter Egg</string>
<!-- name of the Q easter egg, a nonogram-style icon puzzle -->
<string name="q_egg_name" translatable="false">Icon Quiz</string>
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt b/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt
new file mode 100644
index 0000000..f5657ae
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Colors.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import androidx.compose.ui.graphics.Color
+
+/** Various UI colors. */
+object Colors {
+ val Eigengrau = Color(0xFF16161D)
+ val Eigengrau2 = Color(0xFF292936)
+ val Eigengrau3 = Color(0xFF3C3C4F)
+ val Eigengrau4 = Color(0xFFA7A7CA)
+
+ val Console = Color(0xFFB7B7FF)
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/ComposeTools.kt b/packages/EasterEgg/src/com/android/egg/landroid/ComposeTools.kt
new file mode 100644
index 0000000..d040fba
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/ComposeTools.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Dp
+import kotlin.random.Random
+
+@Composable fun Dp.toLocalPx() = with(LocalDensity.current) { this@toLocalPx.toPx() }
+
+operator fun Easing.times(next: Easing) = { x: Float -> next.transform(transform(x)) }
+
+fun flickerFadeEasing(rng: Random) = Easing { frac -> if (rng.nextFloat() < frac) 1f else 0f }
+
+val flickerFadeIn =
+ fadeIn(
+ animationSpec =
+ tween(
+ durationMillis = 1000,
+ easing = CubicBezierEasing(0f, 1f, 1f, 0f) * flickerFadeEasing(Random)
+ )
+ )
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
new file mode 100644
index 0000000..5a9b814
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/MainActivity.kt
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import android.content.res.Resources
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.withInfiniteAnimationFrameNanos
+import androidx.compose.animation.fadeIn
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.border
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.forEachGesture
+import androidx.compose.foundation.gestures.rememberTransformableState
+import androidx.compose.foundation.gestures.transformable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.AbsoluteAlignment.Left
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathEffect
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.Devices
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.core.math.MathUtils.clamp
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.layout.FoldingFeature
+import androidx.window.layout.WindowInfoTracker
+import java.lang.Float.max
+import java.lang.Float.min
+import java.util.Calendar
+import java.util.GregorianCalendar
+import kotlin.math.absoluteValue
+import kotlin.math.floor
+import kotlin.math.sqrt
+import kotlin.random.Random
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+enum class RandomSeedType {
+ Fixed,
+ Daily,
+ Evergreen
+}
+
+const val TEST_UNIVERSE = false
+
+val RANDOM_SEED_TYPE = RandomSeedType.Daily
+
+const val FIXED_RANDOM_SEED = 5038L
+const val DEFAULT_CAMERA_ZOOM = 0.25f
+const val MIN_CAMERA_ZOOM = 250f / UNIVERSE_RANGE // 0.0025f
+const val MAX_CAMERA_ZOOM = 5f
+const val TOUCH_CAMERA_PAN = false
+const val TOUCH_CAMERA_ZOOM = true
+const val DYNAMIC_ZOOM = false // @@@ FIXME
+
+fun dailySeed(): Long {
+ val today = GregorianCalendar()
+ return today.get(Calendar.YEAR) * 10_000L +
+ today.get(Calendar.MONTH) * 100L +
+ today.get(Calendar.DAY_OF_MONTH)
+}
+
+fun randomSeed(): Long {
+ return when (RANDOM_SEED_TYPE) {
+ RandomSeedType.Fixed -> FIXED_RANDOM_SEED
+ RandomSeedType.Daily -> dailySeed()
+ else -> Random.Default.nextLong().mod(10_000_000).toLong()
+ }.absoluteValue
+}
+
+val DEBUG_TEXT = mutableStateOf("Hello Universe")
+const val SHOW_DEBUG_TEXT = false
+
+@Composable
+fun DebugText(text: MutableState<String>) {
+ if (SHOW_DEBUG_TEXT) {
+ Text(
+ modifier = Modifier.fillMaxWidth().border(0.5.dp, color = Color.Yellow).padding(2.dp),
+ fontFamily = FontFamily.Monospace,
+ fontWeight = FontWeight.Medium,
+ fontSize = 9.sp,
+ color = Color.Yellow,
+ text = text.value
+ )
+ }
+}
+
+@Composable
+fun ColumnScope.ConsoleText(
+ modifier: Modifier = Modifier,
+ visible: Boolean = true,
+ random: Random = Random.Default,
+ text: String
+) {
+ AnimatedVisibility(
+ modifier = modifier,
+ visible = visible,
+ enter =
+ fadeIn(
+ animationSpec =
+ tween(
+ durationMillis = 1000,
+ easing = flickerFadeEasing(random) * CubicBezierEasing(0f, 1f, 1f, 0f)
+ )
+ )
+ ) {
+ Text(
+ fontFamily = FontFamily.Monospace,
+ fontWeight = FontWeight.Medium,
+ fontSize = 12.sp,
+ color = Color(0xFFFF8000),
+ text = text
+ )
+ }
+}
+
+@Composable
+fun Telemetry(universe: VisibleUniverse) {
+ var topVisible by remember { mutableStateOf(false) }
+ var bottomVisible by remember { mutableStateOf(false) }
+
+ LaunchedEffect("blah") {
+ delay(1000)
+ bottomVisible = true
+ delay(1000)
+ topVisible = true
+ }
+
+ Column(modifier = Modifier.fillMaxSize().padding(6.dp)) {
+ universe.triggerDraw.value // recompose on every frame
+ val explored = universe.planets.filter { it.explored }
+
+ AnimatedVisibility(modifier = Modifier, visible = topVisible, enter = flickerFadeIn) {
+ Text(
+ fontFamily = FontFamily.Monospace,
+ fontWeight = FontWeight.Medium,
+ fontSize = 12.sp,
+ color = Colors.Console,
+ modifier = Modifier.align(Left),
+ text =
+ with(universe.star) {
+ " STAR: $name (UDC-${universe.randomSeed % 100_000})\n" +
+ " CLASS: ${cls.name}\n" +
+ "RADIUS: ${radius.toInt()}\n" +
+ " MASS: %.3g\n".format(mass) +
+ "BODIES: ${explored.size} / ${universe.planets.size}\n" +
+ "\n"
+ } +
+ explored
+ .map {
+ " BODY: ${it.name}\n" +
+ " TYPE: ${it.description.capitalize()}\n" +
+ " ATMO: ${it.atmosphere.capitalize()}\n" +
+ " FAUNA: ${it.fauna.capitalize()}\n" +
+ " FLORA: ${it.flora.capitalize()}\n"
+ }
+ .joinToString("\n")
+
+ // TODO: different colors, highlight latest discovery
+ )
+ }
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ AnimatedVisibility(modifier = Modifier, visible = bottomVisible, enter = flickerFadeIn) {
+ Text(
+ fontFamily = FontFamily.Monospace,
+ fontWeight = FontWeight.Medium,
+ fontSize = 12.sp,
+ color = Colors.Console,
+ modifier = Modifier.align(Left),
+ text =
+ with(universe.ship) {
+ val closest = universe.closestPlanet()
+ val distToClosest = (closest.pos - pos).mag().toInt()
+ listOfNotNull(
+ landing?.let { "LND: ${it.planet.name}" }
+ ?: if (distToClosest < 10_000) {
+ "ALT: $distToClosest"
+ } else null,
+ if (thrust != Vec2.Zero) "THR: %.0f%%".format(thrust.mag() * 100f)
+ else null,
+ "POS: %s".format(pos.str("%+7.0f")),
+ "VEL: %.0f".format(velocity.mag())
+ )
+ .joinToString("\n")
+ }
+ )
+ }
+ }
+}
+
+class MainActivity : ComponentActivity() {
+ private var foldState = mutableStateOf<FoldingFeature?>(null)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ onWindowLayoutInfoChange()
+
+ val universe = VisibleUniverse(namer = Namer(resources), randomSeed = randomSeed())
+
+ if (TEST_UNIVERSE) {
+ universe.initTest()
+ } else {
+ universe.initRandom()
+ }
+
+ setContent {
+ Spaaaace(modifier = Modifier.fillMaxSize(), u = universe, foldState = foldState)
+ DebugText(DEBUG_TEXT)
+
+ val minRadius = 50.dp.toLocalPx()
+ val maxRadius = 100.dp.toLocalPx()
+ FlightStick(
+ modifier = Modifier.fillMaxSize(),
+ minRadius = minRadius,
+ maxRadius = maxRadius,
+ color = Color.Green
+ ) { vec ->
+ (universe.follow as? Spacecraft)?.let { ship ->
+ if (vec == Vec2.Zero) {
+ ship.thrust = Vec2.Zero
+ } else {
+ val a = vec.angle()
+ ship.angle = a
+
+ val m = vec.mag()
+ if (m < minRadius) {
+ // within this radius, just reorient
+ ship.thrust = Vec2.Zero
+ } else {
+ ship.thrust =
+ Vec2.makeWithAngleMag(
+ a,
+ lexp(minRadius, maxRadius, m).coerceIn(0f, 1f)
+ )
+ }
+ }
+ }
+ }
+ Telemetry(universe)
+ }
+ }
+
+ private fun onWindowLayoutInfoChange() {
+ val windowInfoTracker = WindowInfoTracker.getOrCreate(this@MainActivity)
+
+ lifecycleScope.launch(Dispatchers.Main) {
+ lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ windowInfoTracker.windowLayoutInfo(this@MainActivity).collect { layoutInfo ->
+ foldState.value =
+ layoutInfo.displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull()
+ Log.v("Landroid", "fold updated: $foldState")
+ }
+ }
+ }
+ }
+}
+
+@Preview(name = "phone", device = Devices.PHONE)
+@Preview(name = "fold", device = Devices.FOLDABLE)
+@Preview(name = "tablet", device = Devices.TABLET)
+@Composable
+fun MainActivityPreview() {
+ val universe = VisibleUniverse(namer = Namer(Resources.getSystem()), randomSeed = randomSeed())
+
+ universe.initTest()
+
+ Spaaaace(modifier = Modifier.fillMaxSize(), universe)
+ DebugText(DEBUG_TEXT)
+ Telemetry(universe)
+}
+
+@Composable
+fun FlightStick(
+ modifier: Modifier,
+ minRadius: Float = 0f,
+ maxRadius: Float = 1000f,
+ color: Color = Color.Green,
+ onStickChanged: (vector: Vec2) -> Unit
+) {
+ val origin = remember { mutableStateOf(Vec2.Zero) }
+ val target = remember { mutableStateOf(Vec2.Zero) }
+
+ Box(
+ modifier =
+ modifier
+ .pointerInput(Unit) {
+ forEachGesture {
+ awaitPointerEventScope {
+ // ACTION_DOWN
+ val down = awaitFirstDown(requireUnconsumed = false)
+ origin.value = down.position
+ target.value = down.position
+
+ do {
+ // ACTION_MOVE
+ val event: PointerEvent = awaitPointerEvent()
+ target.value = event.changes[0].position
+
+ onStickChanged(target.value - origin.value)
+ } while (
+ !event.changes.any { it.isConsumed } &&
+ event.changes.count { it.pressed } == 1
+ )
+
+ // ACTION_UP / CANCEL
+ target.value = Vec2.Zero
+ origin.value = Vec2.Zero
+
+ onStickChanged(Vec2.Zero)
+ }
+ }
+ }
+ .drawBehind {
+ if (origin.value != Vec2.Zero) {
+ val delta = target.value - origin.value
+ val mag = min(maxRadius, delta.mag())
+ val r = max(minRadius, mag)
+ val a = delta.angle()
+ drawCircle(
+ color = color,
+ center = origin.value,
+ radius = r,
+ style =
+ Stroke(
+ width = 2f,
+ pathEffect =
+ if (mag < minRadius)
+ PathEffect.dashPathEffect(
+ floatArrayOf(this.density * 1f, this.density * 2f)
+ )
+ else null
+ )
+ )
+ drawLine(
+ color = color,
+ start = origin.value,
+ end = origin.value + Vec2.makeWithAngleMag(a, mag),
+ strokeWidth = 2f
+ )
+ }
+ }
+ )
+}
+
+@Composable
+fun Spaaaace(
+ modifier: Modifier,
+ u: VisibleUniverse,
+ foldState: MutableState<FoldingFeature?> = mutableStateOf(null)
+) {
+ LaunchedEffect(u) {
+ while (true) withInfiniteAnimationFrameNanos { frameTimeNanos ->
+ u.simulateAndDrawFrame(frameTimeNanos)
+ }
+ }
+
+ var cameraZoom by remember { mutableStateOf(1f) }
+ var cameraOffset by remember { mutableStateOf(Offset.Zero) }
+
+ val transformableState =
+ rememberTransformableState { zoomChange, offsetChange, rotationChange ->
+ if (TOUCH_CAMERA_PAN) cameraOffset += offsetChange / cameraZoom
+ if (TOUCH_CAMERA_ZOOM)
+ cameraZoom = clamp(cameraZoom * zoomChange, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM)
+ }
+
+ var canvasModifier = modifier
+
+ if (TOUCH_CAMERA_PAN || TOUCH_CAMERA_ZOOM) {
+ canvasModifier = canvasModifier.transformable(transformableState)
+ }
+
+ val halfFolded = foldState.value?.let { it.state == FoldingFeature.State.HALF_OPENED } ?: false
+ val horizontalFold =
+ foldState.value?.let { it.orientation == FoldingFeature.Orientation.HORIZONTAL } ?: false
+
+ val centerFracX: Float by
+ animateFloatAsState(if (halfFolded && !horizontalFold) 0.25f else 0.5f, label = "centerX")
+ val centerFracY: Float by
+ animateFloatAsState(if (halfFolded && horizontalFold) 0.25f else 0.5f, label = "centerY")
+
+ Canvas(modifier = canvasModifier) {
+ drawRect(Colors.Eigengrau, Offset.Zero, size)
+
+ val closest = u.closestPlanet()
+ val distToNearestSurf = max(0f, (u.ship.pos - closest.pos).mag() - closest.radius * 1.2f)
+ // val normalizedDist = clamp(distToNearestSurf, 50f, 50_000f) / 50_000f
+ if (DYNAMIC_ZOOM) {
+ // cameraZoom = lerp(0.1f, 5f, smooth(1f-normalizedDist))
+ cameraZoom = clamp(500f / distToNearestSurf, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM)
+ } else if (!TOUCH_CAMERA_ZOOM) cameraZoom = DEFAULT_CAMERA_ZOOM
+ if (!TOUCH_CAMERA_PAN) cameraOffset = (u.follow?.pos ?: Vec2.Zero) * -1f
+
+ // cameraZoom: metersToPixels
+ // visibleSpaceSizeMeters: meters
+ // cameraOffset: meters ≈ vector pointing from ship to (0,0) (e.g. -pos)
+ val visibleSpaceSizeMeters = size / cameraZoom // meters x meters
+ val visibleSpaceRectMeters =
+ Rect(
+ -cameraOffset -
+ Offset(
+ visibleSpaceSizeMeters.width * centerFracX,
+ visibleSpaceSizeMeters.height * centerFracY
+ ),
+ visibleSpaceSizeMeters
+ )
+
+ var gridStep = 1000f
+ while (gridStep * cameraZoom < 32.dp.toPx()) gridStep *= 10
+
+ DEBUG_TEXT.value =
+ ("SIMULATION //\n" +
+ // "normalizedDist=${normalizedDist} \n" +
+ "entities: ${u.entities.size} // " +
+ "zoom: ${"%.4f".format(cameraZoom)}x // " +
+ "fps: ${"%3.0f".format(1f / u.dt)} " +
+ "dt: ${u.dt}\n" +
+ ((u.follow as? Spacecraft)?.let {
+ "ship: p=%s v=%7.2f a=%6.3f t=%s\n".format(
+ it.pos.str("%+7.1f"),
+ it.velocity.mag(),
+ it.angle,
+ it.thrust.str("%+5.2f")
+ )
+ }
+ ?: "") +
+ "star: '${u.star.name}' designation=UDC-${u.randomSeed % 100_000} " +
+ "class=${u.star.cls.name} r=${u.star.radius.toInt()} m=${u.star.mass}\n" +
+ "planets: ${u.planets.size}\n" +
+ u.planets.joinToString("\n") {
+ val range = (u.ship.pos - it.pos).mag()
+ val vorbit = sqrt(GRAVITATION * it.mass / range)
+ val vescape = sqrt(2 * GRAVITATION * it.mass / it.radius)
+ " * ${it.name}:\n" +
+ if (it.explored) {
+ " TYPE: ${it.description.capitalize()}\n" +
+ " ATMO: ${it.atmosphere.capitalize()}\n" +
+ " FAUNA: ${it.fauna.capitalize()}\n" +
+ " FLORA: ${it.flora.capitalize()}\n"
+ } else {
+ " (Unexplored)\n"
+ } +
+ " orbit=${(it.pos - it.orbitCenter).mag().toInt()}" +
+ " radius=${it.radius.toInt()}" +
+ " mass=${"%g".format(it.mass)}" +
+ " vel=${(it.speed).toInt()}" +
+ " // range=${"%.0f".format(range)}" +
+ " vorbit=${vorbit.toInt()} vescape=${vescape.toInt()}"
+ })
+
+ zoom(cameraZoom) {
+ // All coordinates are space coordinates now.
+
+ translate(
+ -visibleSpaceRectMeters.center.x + size.width * 0.5f,
+ -visibleSpaceRectMeters.center.y + size.height * 0.5f
+ ) {
+ // debug outer frame
+ // drawRect(
+ // Colors.Eigengrau2,
+ // visibleSpaceRectMeters.topLeft,
+ // visibleSpaceRectMeters.size,
+ // style = Stroke(width = 10f / cameraZoom)
+ // )
+
+ var x = floor(visibleSpaceRectMeters.left / gridStep) * gridStep
+ while (x < visibleSpaceRectMeters.right) {
+ drawLine(
+ color = Colors.Eigengrau2,
+ start = Offset(x, visibleSpaceRectMeters.top),
+ end = Offset(x, visibleSpaceRectMeters.bottom),
+ strokeWidth = (if ((x % (gridStep * 10) == 0f)) 3f else 1.5f) / cameraZoom
+ )
+ x += gridStep
+ }
+
+ var y = floor(visibleSpaceRectMeters.top / gridStep) * gridStep
+ while (y < visibleSpaceRectMeters.bottom) {
+ drawLine(
+ color = Colors.Eigengrau2,
+ start = Offset(visibleSpaceRectMeters.left, y),
+ end = Offset(visibleSpaceRectMeters.right, y),
+ strokeWidth = (if ((y % (gridStep * 10) == 0f)) 3f else 1.5f) / cameraZoom
+ )
+ y += gridStep
+ }
+
+ this@zoom.drawUniverse(u)
+ }
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt b/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt
new file mode 100644
index 0000000..fdf29f7
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Maths.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import kotlin.math.pow
+
+/** smoothstep. Ken Perlin's version */
+fun smooth(x: Float): Float {
+ return x * x * x * (x * (x * 6 - 15) + 10)
+}
+
+/** Kind of like an inverted smoothstep, but */
+fun invsmoothish(x: Float): Float {
+ return 0.25f * ((2f * x - 1f).pow(5f) + 1f) + 0.5f * x
+}
+
+/** Compute the fraction that progress represents between start and end (inverse of lerp). */
+fun lexp(start: Float, end: Float, progress: Float): Float {
+ return (progress - start) / (end - start)
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt b/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt
new file mode 100644
index 0000000..67d536e
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Namer.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import android.content.res.Resources
+import kotlin.random.Random
+
+import com.android.egg.R
+
+const val SUFFIX_PROB = 0.75f
+const val LETTER_PROB = 0.3f
+const val NUMBER_PROB = 0.3f
+const val RARE_PROB = 0.05f
+
+class Namer(resources: Resources) {
+ private val planetDescriptors = Bag(resources.getStringArray(R.array.planet_descriptors))
+ private val lifeDescriptors = Bag(resources.getStringArray(R.array.life_descriptors))
+ private val anyDescriptors = Bag(resources.getStringArray(R.array.any_descriptors))
+ private val atmoDescriptors = Bag(resources.getStringArray(R.array.atmo_descriptors))
+
+ private val planetTypes = Bag(resources.getStringArray(R.array.planet_types))
+ private val constellations = Bag(resources.getStringArray(R.array.constellations))
+ private val constellationsRare = Bag(resources.getStringArray(R.array.constellations_rare))
+ private val suffixes = Bag(resources.getStringArray(R.array.star_suffixes))
+ private val suffixesRare = Bag(resources.getStringArray(R.array.star_suffixes_rare))
+
+ private val planetTable = RandomTable(0.75f to planetDescriptors, 0.25f to anyDescriptors)
+
+ private var lifeTable = RandomTable(0.75f to lifeDescriptors, 0.25f to anyDescriptors)
+
+ private var constellationsTable =
+ RandomTable(RARE_PROB to constellationsRare, 1f - RARE_PROB to constellations)
+
+ private var suffixesTable = RandomTable(RARE_PROB to suffixesRare, 1f - RARE_PROB to suffixes)
+
+ private var atmoTable = RandomTable(0.75f to atmoDescriptors, 0.25f to anyDescriptors)
+
+ private var delimiterTable =
+ RandomTable(
+ 15f to " ",
+ 3f to "-",
+ 1f to "_",
+ 1f to "/",
+ 1f to ".",
+ 1f to "*",
+ 1f to "^",
+ 1f to "#",
+ 0.1f to "(^*!%@##!!"
+ )
+
+ fun describePlanet(rng: Random): String {
+ return planetTable.roll(rng).pull(rng) + " " + planetTypes.pull(rng)
+ }
+
+ fun describeLife(rng: Random): String {
+ return lifeTable.roll(rng).pull(rng)
+ }
+
+ fun nameSystem(rng: Random): String {
+ val parts = StringBuilder()
+ parts.append(constellationsTable.roll(rng).pull(rng))
+ if (rng.nextFloat() <= SUFFIX_PROB) {
+ parts.append(delimiterTable.roll(rng))
+ parts.append(suffixesTable.roll(rng).pull(rng))
+ if (rng.nextFloat() <= RARE_PROB) parts.append(' ').append(suffixesRare.pull(rng))
+ }
+ if (rng.nextFloat() <= LETTER_PROB) {
+ parts.append(delimiterTable.roll(rng))
+ parts.append('A' + rng.nextInt(0, 26))
+ if (rng.nextFloat() <= RARE_PROB) parts.append(delimiterTable.roll(rng))
+ }
+ if (rng.nextFloat() <= NUMBER_PROB) {
+ parts.append(delimiterTable.roll(rng))
+ parts.append(rng.nextInt(2, 5039))
+ }
+ return parts.toString()
+ }
+
+ fun describeAtmo(rng: Random): String {
+ return atmoTable.roll(rng).pull(rng)
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt b/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt
new file mode 100644
index 0000000..8510640
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/PathTools.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import android.util.Log
+import androidx.compose.ui.graphics.Path
+import kotlin.math.cos
+import kotlin.math.sin
+
+fun createPolygon(radius: Float, sides: Int): Path {
+ return Path().apply {
+ moveTo(radius, 0f)
+ val angleStep = PI2f / sides
+ for (i in 1 until sides) {
+ lineTo(radius * cos(angleStep * i), radius * sin(angleStep * i))
+ }
+ close()
+ }
+}
+
+fun createStar(radius1: Float, radius2: Float, points: Int): Path {
+ return Path().apply {
+ val angleStep = PI2f / points
+ moveTo(radius1, 0f)
+ lineTo(radius2 * cos(angleStep * (0.5f)), radius2 * sin(angleStep * (0.5f)))
+ for (i in 1 until points) {
+ lineTo(radius1 * cos(angleStep * i), radius1 * sin(angleStep * i))
+ lineTo(radius2 * cos(angleStep * (i + 0.5f)), radius2 * sin(angleStep * (i + 0.5f)))
+ }
+ close()
+ }
+}
+
+fun Path.parseSvgPathData(d: String) {
+ Regex("([A-Z])([-.,0-9e ]+)").findAll(d.trim()).forEach {
+ val cmd = it.groups[1]!!.value
+ val args =
+ it.groups[2]?.value?.split(Regex("\\s+"))?.map { v -> v.toFloat() } ?: emptyList()
+ Log.d("Landroid", "cmd = $cmd, args = " + args.joinToString(","))
+ when (cmd) {
+ "M" -> moveTo(args[0], args[1])
+ "C" -> cubicTo(args[0], args[1], args[2], args[3], args[4], args[5])
+ "L" -> lineTo(args[0], args[1])
+ "Z" -> close()
+ else -> Log.v("Landroid", "unsupported SVG command: $cmd")
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
new file mode 100644
index 0000000..fc66ad6
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import android.util.ArraySet
+import kotlin.random.Random
+
+// artificially speed up or slow down the simulation
+const val TIME_SCALE = 1f
+
+// if it's been over 1 real second since our last timestep, don't simulate that elapsed time.
+// this allows the simulation to "pause" when, for example, the activity pauses
+const val MAX_VALID_DT = 1f
+
+interface Entity {
+ // Integrate.
+ // Compute accelerations from forces, add accelerations to velocity, save old position,
+ // add velocity to position.
+ fun update(sim: Simulator, dt: Float)
+
+ // Post-integration step, after constraints are satisfied.
+ fun postUpdate(sim: Simulator, dt: Float)
+}
+
+open class Body(var name: String = "Unknown") : Entity {
+ var pos = Vec2.Zero
+ var opos = Vec2.Zero
+ var velocity = Vec2.Zero
+
+ var mass = 0f
+ var angle = 0f
+ var radius = 0f
+
+ var collides = true
+
+ var omega: Float
+ get() = angle - oangle
+ set(value) {
+ oangle = angle - value
+ }
+
+ var oangle = 0f
+
+ override fun update(sim: Simulator, dt: Float) {
+ if (dt <= 0) return
+
+ // integrate velocity
+ val vscaled = velocity * dt
+ opos = pos
+ pos += vscaled
+
+ // integrate angular velocity
+ // val wscaled = omega * timescale
+ // oangle = angle
+ // angle = (angle + wscaled) % PI2f
+ }
+
+ override fun postUpdate(sim: Simulator, dt: Float) {
+ if (dt <= 0) return
+ velocity = (pos - opos) / dt
+ }
+}
+
+interface Constraint {
+ // Solve constraints. Pick up objects and put them where they are "supposed" to be.
+ fun solve(sim: Simulator, dt: Float)
+}
+
+open class Container(val radius: Float) : Constraint {
+ private val list = ArraySet<Body>()
+ private val softness = 0.0f
+
+ override fun toString(): String {
+ return "Container($radius)"
+ }
+
+ fun add(p: Body) {
+ list.add(p)
+ }
+
+ fun remove(p: Body) {
+ list.remove(p)
+ }
+
+ override fun solve(sim: Simulator, dt: Float) {
+ for (p in list) {
+ if ((p.pos.mag() + p.radius) > radius) {
+ p.pos =
+ p.pos * (softness) +
+ Vec2.makeWithAngleMag(p.pos.angle(), radius - p.radius) * (1f - softness)
+ }
+ }
+ }
+}
+
+open class Simulator(val randomSeed: Long) {
+ private var wallClockNanos: Long = 0L
+ var now: Float = 0f
+ var dt: Float = 0f
+ val rng = Random(randomSeed)
+ val entities = ArraySet<Entity>(1000)
+ val constraints = ArraySet<Constraint>(100)
+
+ fun add(e: Entity) = entities.add(e)
+ fun remove(e: Entity) = entities.remove(e)
+ fun add(c: Constraint) = constraints.add(c)
+ fun remove(c: Constraint) = constraints.remove(c)
+
+ open fun updateAll(dt: Float, entities: ArraySet<Entity>) {
+ entities.forEach { it.update(this, dt) }
+ }
+
+ open fun solveAll(dt: Float, constraints: ArraySet<Constraint>) {
+ constraints.forEach { it.solve(this, dt) }
+ }
+
+ open fun postUpdateAll(dt: Float, entities: ArraySet<Entity>) {
+ entities.forEach { it.postUpdate(this, dt) }
+ }
+
+ fun step(nanos: Long) {
+ val firstFrame = (wallClockNanos == 0L)
+
+ dt = (nanos - wallClockNanos) / 1_000_000_000f * TIME_SCALE
+ this.wallClockNanos = nanos
+
+ // we start the simulation on the next frame
+ if (firstFrame || dt > MAX_VALID_DT) return
+
+ // simulation is running; we start accumulating simulation time
+ this.now += dt
+
+ val localEntities = ArraySet(entities)
+ val localConstraints = ArraySet(constraints)
+
+ // position-based dynamics approach:
+ // 1. apply acceleration to velocity, save positions, apply velocity to position
+ updateAll(dt, localEntities)
+
+ // 2. solve all constraints
+ solveAll(dt, localConstraints)
+
+ // 3. compute new velocities from updated positions and saved positions
+ postUpdateAll(dt, localEntities)
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt b/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt
new file mode 100644
index 0000000..ebbb2bd
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Randomness.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import kotlin.random.Random
+
+/**
+ * A bag of stones. Each time you pull one out it is not replaced, preventing duplicates. When the
+ * bag is exhausted, all the stones are replaced and reshuffled.
+ */
+class Bag<T>(items: Array<T>) {
+ private val remaining = items.copyOf()
+ private var next = remaining.size // will cause a shuffle on first pull()
+
+ /** Return the next random item from the bag, without replacing it. */
+ fun pull(rng: Random): T {
+ if (next >= remaining.size) {
+ remaining.shuffle(rng)
+ next = 0
+ }
+ return remaining[next++]
+ }
+}
+
+/**
+ * A loot table. The weight of each possibility is in the first of the pair; the value to be
+ * returned in the second. They need not add up to 1f (we will do that for you, free of charge).
+ */
+class RandomTable<T>(private vararg val pairs: Pair<Float, T>) {
+ private val total = pairs.map { it.first }.sum()
+
+ /** Select a random value from the weighted table. */
+ fun roll(rng: Random): T {
+ var x = rng.nextFloatInRange(0f, total)
+ for ((weight, result) in pairs) {
+ x -= weight
+ if (x < 0f) return result
+ }
+ return pairs.last().second
+ }
+}
+
+/** Return a random float in the range [from, until). */
+fun Random.nextFloatInRange(from: Float, until: Float): Float =
+ from + ((until - from) * nextFloat())
+
+/** Return a random float in the range [start, end). */
+fun Random.nextFloatInRange(fromUntil: ClosedFloatingPointRange<Float>): Float =
+ nextFloatInRange(fromUntil.start, fromUntil.endInclusive)
+/** Return a random float in the range [first, second). */
+fun Random.nextFloatInRange(fromUntil: Pair<Float, Float>): Float =
+ nextFloatInRange(fromUntil.first, fromUntil.second)
+
+/** Choose a random element from an array. */
+fun <T> Random.choose(array: Array<T>) = array[nextInt(array.size)]
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
new file mode 100644
index 0000000..fec3ab3
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import android.util.ArraySet
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.util.lerp
+import kotlin.math.absoluteValue
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+const val UNIVERSE_RANGE = 200_000f
+
+val NUM_PLANETS_RANGE = 1..10
+val STAR_RADIUS_RANGE = (1_000f..8_000f)
+val PLANET_RADIUS_RANGE = (50f..2_000f)
+val PLANET_ORBIT_RANGE = (STAR_RADIUS_RANGE.endInclusive * 2f)..(UNIVERSE_RANGE * 0.75f)
+
+const val GRAVITATION = 1e-2f
+const val KEPLER_CONSTANT = 50f // * 4f * PIf * PIf / GRAVITATION
+
+// m = d * r
+const val PLANETARY_DENSITY = 2.5f
+const val STELLAR_DENSITY = 0.5f
+
+const val SPACECRAFT_MASS = 10f
+
+const val CRAFT_SPEED_LIMIT = 5_000f
+const val MAIN_ENGINE_ACCEL = 1000f // thrust effect, pixels per second squared
+const val LAUNCH_MECO = 2f // how long to suspend gravity when launching
+
+const val SCALED_THRUST = true
+
+interface Removable {
+ fun canBeRemoved(): Boolean
+}
+
+open class Planet(
+ val orbitCenter: Vec2,
+ radius: Float,
+ pos: Vec2,
+ var speed: Float,
+ var color: Color = Color.White
+) : Body() {
+ var atmosphere = ""
+ var description = ""
+ var flora = ""
+ var fauna = ""
+ var explored = false
+ private val orbitRadius: Float
+ init {
+ this.radius = radius
+ this.pos = pos
+ orbitRadius = pos.distance(orbitCenter)
+ mass = 4 / 3 * PIf * radius.pow(3) * PLANETARY_DENSITY
+ }
+
+ override fun update(sim: Simulator, dt: Float) {
+ val orbitAngle = (pos - orbitCenter).angle()
+ // constant linear velocity
+ velocity = Vec2.makeWithAngleMag(orbitAngle + PIf / 2f, speed)
+
+ super.update(sim, dt)
+ }
+
+ override fun postUpdate(sim: Simulator, dt: Float) {
+ // This is kind of like a constraint, but whatever.
+ val orbitAngle = (pos - orbitCenter).angle()
+ pos = orbitCenter + Vec2.makeWithAngleMag(orbitAngle, orbitRadius)
+ super.postUpdate(sim, dt)
+ }
+}
+
+enum class StarClass {
+ O,
+ B,
+ A,
+ F,
+ G,
+ K,
+ M
+}
+
+fun starColor(cls: StarClass) =
+ when (cls) {
+ StarClass.O -> Color(0xFF6666FF)
+ StarClass.B -> Color(0xFFCCCCFF)
+ StarClass.A -> Color(0xFFEEEEFF)
+ StarClass.F -> Color(0xFFFFFFFF)
+ StarClass.G -> Color(0xFFFFFF66)
+ StarClass.K -> Color(0xFFFFCC33)
+ StarClass.M -> Color(0xFFFF8800)
+ }
+
+class Star(val cls: StarClass, radius: Float) :
+ Planet(orbitCenter = Vec2.Zero, radius = radius, pos = Vec2.Zero, speed = 0f) {
+ init {
+ pos = Vec2.Zero
+ mass = 4 / 3 * PIf * radius.pow(3) * STELLAR_DENSITY
+ color = starColor(cls)
+ collides = false
+ }
+ var anim = 0f
+ override fun update(sim: Simulator, dt: Float) {
+ anim += dt
+ }
+}
+
+open class Universe(val namer: Namer, randomSeed: Long) : Simulator(randomSeed) {
+ var latestDiscovery: Planet? = null
+ lateinit var star: Star
+ lateinit var ship: Spacecraft
+ val planets: MutableList<Planet> = mutableListOf()
+ var follow: Body? = null
+ val ringfence = Container(UNIVERSE_RANGE)
+
+ fun initTest() {
+ val systemName = "TEST SYSTEM"
+ star =
+ Star(
+ cls = StarClass.A,
+ radius = STAR_RADIUS_RANGE.endInclusive,
+ )
+ .apply { name = "TEST SYSTEM" }
+
+ repeat(NUM_PLANETS_RANGE.last) {
+ val thisPlanetFrac = it.toFloat() / (NUM_PLANETS_RANGE.last - 1)
+ val radius =
+ lerp(PLANET_RADIUS_RANGE.start, PLANET_RADIUS_RANGE.endInclusive, thisPlanetFrac)
+ val orbitRadius =
+ lerp(PLANET_ORBIT_RANGE.start, PLANET_ORBIT_RANGE.endInclusive, thisPlanetFrac)
+
+ val period = sqrt(orbitRadius.pow(3f) / star.mass) * KEPLER_CONSTANT
+ val speed = 2f * PIf * orbitRadius / period
+
+ val p =
+ Planet(
+ orbitCenter = star.pos,
+ radius = radius,
+ pos = star.pos + Vec2.makeWithAngleMag(thisPlanetFrac * PI2f, orbitRadius),
+ speed = speed,
+ color = Colors.Eigengrau4
+ )
+ android.util.Log.v(
+ "Landroid",
+ "created planet $p with period $period and vel $speed"
+ )
+ val num = it + 1
+ p.description = "TEST PLANET #$num"
+ p.atmosphere = "radius=$radius"
+ p.flora = "mass=${p.mass}"
+ p.fauna = "speed=$speed"
+ planets.add(p)
+ add(p)
+ }
+
+ planets.sortBy { it.pos.distance(star.pos) }
+ planets.forEachIndexed { idx, planet -> planet.name = "$systemName ${idx + 1}" }
+ add(star)
+
+ ship = Spacecraft()
+
+ ship.pos = star.pos + Vec2.makeWithAngleMag(PIf / 4, PLANET_ORBIT_RANGE.start)
+ ship.angle = 0f
+ add(ship)
+
+ ringfence.add(ship)
+ add(ringfence)
+
+ follow = ship
+ }
+
+ fun initRandom() {
+ val systemName = namer.nameSystem(rng)
+ star =
+ Star(
+ cls = rng.choose(StarClass.values()),
+ radius = rng.nextFloatInRange(STAR_RADIUS_RANGE)
+ )
+ star.name = systemName
+ repeat(rng.nextInt(NUM_PLANETS_RANGE.first, NUM_PLANETS_RANGE.last + 1)) {
+ val radius = rng.nextFloatInRange(PLANET_RADIUS_RANGE)
+ val orbitRadius =
+ lerp(
+ PLANET_ORBIT_RANGE.start,
+ PLANET_ORBIT_RANGE.endInclusive,
+ rng.nextFloat().pow(1f)
+ )
+
+ // Kepler's third law
+ val period = sqrt(orbitRadius.pow(3f) / star.mass) * KEPLER_CONSTANT
+ val speed = 2f * PIf * orbitRadius / period
+
+ val p =
+ Planet(
+ orbitCenter = star.pos,
+ radius = radius,
+ pos = star.pos + Vec2.makeWithAngleMag(rng.nextFloat() * PI2f, orbitRadius),
+ speed = speed,
+ color = Colors.Eigengrau4
+ )
+ android.util.Log.v(
+ "Landroid",
+ "created planet $p with period $period and vel $speed"
+ )
+ p.description = namer.describePlanet(rng)
+ p.atmosphere = namer.describeAtmo(rng)
+ p.flora = namer.describeLife(rng)
+ p.fauna = namer.describeLife(rng)
+ planets.add(p)
+ add(p)
+ }
+ planets.sortBy { it.pos.distance(star.pos) }
+ planets.forEachIndexed { idx, planet -> planet.name = "$systemName ${idx + 1}" }
+ add(star)
+
+ ship = Spacecraft()
+
+ ship.pos =
+ star.pos +
+ Vec2.makeWithAngleMag(
+ rng.nextFloat() * PI2f,
+ rng.nextFloatInRange(PLANET_ORBIT_RANGE.start, PLANET_ORBIT_RANGE.endInclusive)
+ )
+ ship.angle = rng.nextFloat() * PI2f
+ add(ship)
+
+ ringfence.add(ship)
+ add(ringfence)
+
+ follow = ship
+ }
+
+ override fun updateAll(dt: Float, entities: ArraySet<Entity>) {
+ // check for passing in front of the sun
+ ship.transit = false
+
+ (planets + star).forEach { planet ->
+ val vector = planet.pos - ship.pos
+ val d = vector.mag()
+ if (d < planet.radius) {
+ if (planet is Star) ship.transit = true
+ } else if (
+ now > ship.launchClock + LAUNCH_MECO
+ ) { // within MECO sec of launch, no gravity at all
+ // simulate gravity: $ f_g = G * m1 * m2 * 1/d^2 $
+ ship.velocity =
+ ship.velocity +
+ Vec2.makeWithAngleMag(
+ vector.angle(),
+ GRAVITATION * (ship.mass * planet.mass) / d.pow(2)
+ ) * dt
+ }
+ }
+
+ super.updateAll(dt, entities)
+ }
+
+ fun closestPlanet(): Planet {
+ val bodiesByDist =
+ (planets + star)
+ .map { planet -> (planet.pos - ship.pos) to planet }
+ .sortedBy { it.first.mag() }
+
+ return bodiesByDist[0].second
+ }
+
+ override fun solveAll(dt: Float, constraints: ArraySet<Constraint>) {
+ if (ship.landing == null) {
+ val planet = closestPlanet()
+
+ if (planet.collides) {
+ val d = (ship.pos - planet.pos).mag() - ship.radius - planet.radius
+ val a = (ship.pos - planet.pos).angle()
+
+ if (d < 0) {
+ // landing, or impact?
+
+ // 1. relative speed
+ val vDiff = (ship.velocity - planet.velocity).mag()
+ // 2. landing angle
+ val aDiff = (ship.angle - a).absoluteValue
+
+ // landing criteria
+ if (aDiff < PIf / 4
+ // &&
+ // vDiff < 100f
+ ) {
+ val landing = Landing(ship, planet, a)
+ ship.landing = landing
+ ship.velocity = planet.velocity
+ add(landing)
+
+ planet.explored = true
+ latestDiscovery = planet
+ } else {
+ val impact = planet.pos + Vec2.makeWithAngleMag(a, planet.radius)
+ ship.pos =
+ planet.pos + Vec2.makeWithAngleMag(a, planet.radius + ship.radius - d)
+
+ // add(Spark(
+ // lifetime = 1f,
+ // style = Spark.Style.DOT,
+ // color = Color.Yellow,
+ // size = 10f
+ // ).apply {
+ // pos = impact
+ // opos = impact
+ // velocity = Vec2.Zero
+ // })
+ //
+ (1..10).forEach {
+ Spark(
+ lifetime = rng.nextFloatInRange(0.5f, 2f),
+ style = Spark.Style.DOT,
+ color = Color.White,
+ size = 1f
+ )
+ .apply {
+ pos =
+ impact +
+ Vec2.makeWithAngleMag(
+ rng.nextFloatInRange(0f, 2 * PIf),
+ rng.nextFloatInRange(0.1f, 0.5f)
+ )
+ opos = pos
+ velocity =
+ ship.velocity * 0.8f +
+ Vec2.makeWithAngleMag(
+ // a +
+ // rng.nextFloatInRange(-PIf, PIf),
+ rng.nextFloatInRange(0f, 2 * PIf),
+ rng.nextFloatInRange(0.1f, 0.5f)
+ )
+ add(this)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ super.solveAll(dt, constraints)
+ }
+
+ override fun postUpdateAll(dt: Float, entities: ArraySet<Entity>) {
+ super.postUpdateAll(dt, entities)
+
+ entities
+ .filterIsInstance<Removable>()
+ .filter(predicate = Removable::canBeRemoved)
+ .filterIsInstance<Entity>()
+ .forEach { remove(it) }
+ }
+}
+
+class Landing(val ship: Spacecraft, val planet: Planet, val angle: Float) : Constraint {
+ private val landingVector = Vec2.makeWithAngleMag(angle, ship.radius + planet.radius)
+ override fun solve(sim: Simulator, dt: Float) {
+ val desiredPos = planet.pos + landingVector
+ ship.pos = (ship.pos * 0.5f) + (desiredPos * 0.5f) // @@@ FIXME
+ ship.angle = angle
+ }
+}
+
+class Spark(
+ var lifetime: Float,
+ collides: Boolean = false,
+ mass: Float = 0f,
+ val style: Style = Style.LINE,
+ val color: Color = Color.Gray,
+ val size: Float = 2f
+) : Removable, Body() {
+ enum class Style {
+ LINE,
+ LINE_ABSOLUTE,
+ DOT,
+ DOT_ABSOLUTE,
+ RING
+ }
+
+ init {
+ this.collides = collides
+ this.mass = mass
+ }
+ override fun update(sim: Simulator, dt: Float) {
+ super.update(sim, dt)
+ lifetime -= dt
+ }
+ override fun canBeRemoved(): Boolean {
+ return lifetime < 0
+ }
+}
+
+const val TRACK_LENGTH = 10_000
+const val SIMPLE_TRACK_DRAWING = true
+
+class Track {
+ val positions = ArrayDeque<Vec2>(TRACK_LENGTH)
+ private val angles = ArrayDeque<Float>(TRACK_LENGTH)
+ fun add(x: Float, y: Float, a: Float) {
+ if (positions.size >= (TRACK_LENGTH - 1)) {
+ positions.removeFirst()
+ angles.removeFirst()
+ positions.removeFirst()
+ angles.removeFirst()
+ }
+ positions.addLast(Vec2(x, y))
+ angles.addLast(a)
+ }
+}
+
+class Spacecraft : Body() {
+ var thrust = Vec2.Zero
+ var launchClock = 0f
+
+ var transit = false
+
+ val track = Track()
+
+ var landing: Landing? = null
+
+ init {
+ mass = SPACECRAFT_MASS
+ radius = 12f
+ }
+
+ override fun update(sim: Simulator, dt: Float) {
+ // check for thrusters
+ val thrustMag = thrust.mag()
+ if (thrustMag > 0) {
+ var deltaV = MAIN_ENGINE_ACCEL * dt
+ if (SCALED_THRUST) deltaV *= thrustMag.coerceIn(0f, 1f)
+
+ if (landing == null) {
+ // we are free in space, so we attempt to pivot toward the desired direction
+ // NOTE: no longer required thanks to FlightStick
+ // angle = thrust.angle()
+ } else
+ landing?.let { landing ->
+ if (launchClock == 0f) launchClock = sim.now + 1f /* @@@ TODO extract */
+
+ if (sim.now > launchClock) {
+ // first-stage to orbit has 1000x power
+ // deltaV *= 1000f
+ sim.remove(landing)
+ this.landing = null
+ } else {
+ deltaV = 0f
+ }
+ }
+
+ // this is it. impart thrust to the ship.
+ // note that we always thrust in the forward direction
+ velocity += Vec2.makeWithAngleMag(angle, deltaV)
+ } else {
+ if (launchClock != 0f) launchClock = 0f
+ }
+
+ // apply global speed limit
+ if (velocity.mag() > CRAFT_SPEED_LIMIT)
+ velocity = Vec2.makeWithAngleMag(velocity.angle(), CRAFT_SPEED_LIMIT)
+
+ super.update(sim, dt)
+ }
+
+ override fun postUpdate(sim: Simulator, dt: Float) {
+ super.postUpdate(sim, dt)
+
+ // special effects all need to be added after the simulation step so they have
+ // the correct position of the ship.
+ track.add(pos.x, pos.y, angle)
+
+ val mag = thrust.mag()
+ if (sim.rng.nextFloat() < mag) {
+ // exhaust
+ sim.add(
+ Spark(
+ lifetime = sim.rng.nextFloatInRange(0.5f, 1f),
+ collides = true,
+ mass = 1f,
+ style = Spark.Style.RING,
+ size = 3f,
+ color = Color(0x40FFFFFF)
+ )
+ .also { spark ->
+ spark.pos = pos
+ spark.opos = pos
+ spark.velocity =
+ velocity +
+ Vec2.makeWithAngleMag(
+ angle + sim.rng.nextFloatInRange(-0.2f, 0.2f),
+ -MAIN_ENGINE_ACCEL * mag * 10f * dt
+ )
+ }
+ )
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Vec2.kt b/packages/EasterEgg/src/com/android/egg/landroid/Vec2.kt
new file mode 100644
index 0000000..82bae75
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Vec2.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import androidx.compose.ui.geometry.Offset
+import kotlin.math.PI
+import kotlin.math.atan2
+import kotlin.math.cos
+import kotlin.math.sin
+
+const val PIf = PI.toFloat()
+const val PI2f = (2 * PI).toFloat()
+
+typealias Vec2 = Offset
+
+fun Vec2.str(fmt: String = "%+.2f"): String = "<$fmt,$fmt>".format(x, y)
+
+fun Vec2(x: Float, y: Float): Vec2 = Offset(x, y)
+
+fun Vec2.mag(): Float {
+ return getDistance()
+}
+
+fun Vec2.distance(other: Vec2): Float {
+ return (this - other).mag()
+}
+
+fun Vec2.angle(): Float {
+ return atan2(y, x)
+}
+
+fun Vec2.dot(o: Vec2): Float {
+ return x * o.x + y * o.y
+}
+
+fun Vec2.product(f: Float): Vec2 {
+ return Vec2(x * f, y * f)
+}
+
+fun Offset.Companion.makeWithAngleMag(a: Float, m: Float): Vec2 {
+ return Vec2(m * cos(a), m * sin(a))
+}
+
+fun Vec2.rotate(angle: Float, origin: Vec2 = Vec2.Zero): Offset {
+ val translated = this - origin
+ return origin +
+ Offset(
+ (translated.x * cos(angle) - translated.y * sin(angle)),
+ (translated.x * sin(angle) + translated.y * cos(angle))
+ )
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
new file mode 100644
index 0000000..24b9c6a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.egg.landroid
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.PathEffect
+import androidx.compose.ui.graphics.PointMode
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.rotateRad
+import androidx.compose.ui.graphics.drawscope.scale
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.util.lerp
+import androidx.core.math.MathUtils.clamp
+import java.lang.Float.max
+import kotlin.math.sqrt
+
+const val DRAW_ORBITS = true
+const val DRAW_GRAVITATIONAL_FIELDS = true
+const val DRAW_STAR_GRAVITATIONAL_FIELDS = true
+
+val STAR_POINTS = android.os.Build.VERSION.SDK_INT.takeIf { it in 1..99 } ?: 31
+
+/**
+ * A zoomedDrawScope is one that is scaled, but remembers its zoom level, so you can correct for it
+ * if you want to draw single-pixel lines. Which we do.
+ */
+interface ZoomedDrawScope : DrawScope {
+ val zoom: Float
+}
+
+fun DrawScope.zoom(zoom: Float, block: ZoomedDrawScope.() -> Unit) {
+ val ds =
+ object : ZoomedDrawScope, DrawScope by this {
+ override var zoom = zoom
+ }
+ ds.scale(zoom) { block(ds) }
+}
+
+class VisibleUniverse(namer: Namer, randomSeed: Long) : Universe(namer, randomSeed) {
+ // Magic variable. Every time we update it, Compose will notice and redraw the universe.
+ val triggerDraw = mutableStateOf(0L)
+
+ fun simulateAndDrawFrame(nanos: Long) {
+ // By writing this value, Compose will look for functions that read it (like drawZoomed).
+ triggerDraw.value = nanos
+
+ step(nanos)
+ }
+}
+
+fun ZoomedDrawScope.drawUniverse(universe: VisibleUniverse) {
+ with(universe) {
+ triggerDraw.value // Please recompose when this value changes.
+
+ // star.drawZoomed(ds, zoom)
+ // planets.forEach { p ->
+ // p.drawZoomed(ds, zoom)
+ // if (p == follow) {
+ // drawCircle(Color.Red, 20f / zoom, p.pos)
+ // }
+ // }
+ //
+ // ship.drawZoomed(ds, zoom)
+
+ constraints.forEach {
+ when (it) {
+ is Landing -> drawLanding(it)
+ is Container -> drawContainer(it)
+ }
+ }
+ drawStar(star)
+ entities.forEach {
+ if (it === ship || it === star) return@forEach // draw the ship last
+ when (it) {
+ is Spacecraft -> drawSpacecraft(it)
+ is Spark -> drawSpark(it)
+ is Planet -> drawPlanet(it)
+ }
+ }
+ drawSpacecraft(ship)
+ }
+}
+
+fun ZoomedDrawScope.drawContainer(container: Container) {
+ drawCircle(
+ color = Color(0xFF800000),
+ radius = container.radius,
+ center = Vec2.Zero,
+ style =
+ Stroke(
+ width = 1f / zoom,
+ pathEffect = PathEffect.dashPathEffect(floatArrayOf(8f / zoom, 8f / zoom), 0f)
+ )
+ )
+ // val path = Path().apply {
+ // fillType = PathFillType.EvenOdd
+ // addOval(Rect(center = Vec2.Zero, radius = container.radius))
+ // addOval(Rect(center = Vec2.Zero, radius = container.radius + 10_000))
+ // }
+ // drawPath(
+ // path = path,
+ //
+ // )
+}
+
+fun ZoomedDrawScope.drawGravitationalField(planet: Planet) {
+ val rings = 8
+ for (i in 0 until rings) {
+ val force =
+ lerp(
+ 200f,
+ 0.01f,
+ i.toFloat() / rings
+ ) // first rings at force = 1N, dropping off after that
+ val r = sqrt(GRAVITATION * planet.mass * SPACECRAFT_MASS / force)
+ drawCircle(
+ color = Color(1f, 0f, 0f, lerp(0.5f, 0.1f, i.toFloat() / rings)),
+ center = planet.pos,
+ style = Stroke(2f / zoom),
+ radius = r
+ )
+ }
+}
+
+fun ZoomedDrawScope.drawPlanet(planet: Planet) {
+ with(planet) {
+ if (DRAW_ORBITS)
+ drawCircle(
+ color = Color(0x8000FFFF),
+ radius = pos.distance(orbitCenter),
+ center = orbitCenter,
+ style =
+ Stroke(
+ width = 1f / zoom,
+ )
+ )
+
+ if (DRAW_GRAVITATIONAL_FIELDS) {
+ drawGravitationalField(this)
+ }
+
+ drawCircle(color = Colors.Eigengrau, radius = radius, center = pos)
+ drawCircle(color = color, radius = radius, center = pos, style = Stroke(2f / zoom))
+ }
+}
+
+fun ZoomedDrawScope.drawStar(star: Star) {
+ translate(star.pos.x, star.pos.y) {
+ drawCircle(color = star.color, radius = star.radius, center = Vec2.Zero)
+
+ if (DRAW_STAR_GRAVITATIONAL_FIELDS) this@drawStar.drawGravitationalField(star)
+
+ rotateRad(radians = star.anim / 23f * PI2f, pivot = Vec2.Zero) {
+ drawPath(
+ path =
+ createStar(
+ radius1 = star.radius + 80,
+ radius2 = star.radius + 250,
+ points = STAR_POINTS
+ ),
+ color = star.color,
+ style =
+ Stroke(
+ width = 3f / this@drawStar.zoom,
+ pathEffect = PathEffect.cornerPathEffect(radius = 200f)
+ )
+ )
+ }
+ rotateRad(radians = star.anim / -19f * PI2f, pivot = Vec2.Zero) {
+ drawPath(
+ path =
+ createStar(
+ radius1 = star.radius + 20,
+ radius2 = star.radius + 200,
+ points = STAR_POINTS + 1
+ ),
+ color = star.color,
+ style =
+ Stroke(
+ width = 3f / this@drawStar.zoom,
+ pathEffect = PathEffect.cornerPathEffect(radius = 200f)
+ )
+ )
+ }
+ }
+}
+
+val spaceshipPath =
+ Path().apply {
+ parseSvgPathData(
+ """
+M11.853 0
+C11.853 -4.418 8.374 -8 4.083 -8
+L-5.5 -8
+C-6.328 -8 -7 -7.328 -7 -6.5
+C-7 -5.672 -6.328 -5 -5.5 -5
+L-2.917 -5
+C-1.26 -5 0.083 -3.657 0.083 -2
+L0.083 2
+C0.083 3.657 -1.26 5 -2.917 5
+L-5.5 5
+C-6.328 5 -7 5.672 -7 6.5
+C-7 7.328 -6.328 8 -5.5 8
+L4.083 8
+C8.374 8 11.853 4.418 11.853 0
+Z
+"""
+ )
+ }
+val thrustPath = createPolygon(-3f, 3).also { it.translate(Vec2(-4f, 0f)) }
+
+fun ZoomedDrawScope.drawSpacecraft(ship: Spacecraft) {
+ with(ship) {
+ rotateRad(angle, pivot = pos) {
+ translate(pos.x, pos.y) {
+ // drawPath(
+ // path = createStar(200f, 100f, 3),
+ // color = Color.White,
+ // style = Stroke(width = 2f / zoom)
+ // )
+ drawPath(path = spaceshipPath, color = Colors.Eigengrau) // fauxpaque
+ drawPath(
+ path = spaceshipPath,
+ color = if (transit) Color.Black else Color.White,
+ style = Stroke(width = 2f / this@drawSpacecraft.zoom)
+ )
+ if (thrust != Vec2.Zero) {
+ drawPath(
+ path = thrustPath,
+ color = Color(0xFFFF8800),
+ style =
+ Stroke(
+ width = 2f / this@drawSpacecraft.zoom,
+ pathEffect = PathEffect.cornerPathEffect(radius = 1f)
+ )
+ )
+ }
+ // drawRect(
+ // topLeft = Offset(-1f, -1f),
+ // size = Size(2f, 2f),
+ // color = Color.Cyan,
+ // style = Stroke(width = 2f / zoom)
+ // )
+ // drawLine(
+ // start = Vec2.Zero,
+ // end = Vec2(20f, 0f),
+ // color = Color.Cyan,
+ // strokeWidth = 2f / zoom
+ // )
+ }
+ }
+ // // DEBUG: draw velocity vector
+ // drawLine(
+ // start = pos,
+ // end = pos + velocity,
+ // color = Color.Red,
+ // strokeWidth = 3f / zoom
+ // )
+ drawTrack(track)
+ }
+}
+
+fun ZoomedDrawScope.drawLanding(landing: Landing) {
+ val v = landing.planet.pos + Vec2.makeWithAngleMag(landing.angle, landing.planet.radius)
+ drawLine(Color.Red, v + Vec2(-5f, -5f), v + Vec2(5f, 5f), strokeWidth = 1f / zoom)
+ drawLine(Color.Red, v + Vec2(5f, -5f), v + Vec2(-5f, 5f), strokeWidth = 1f / zoom)
+}
+
+fun ZoomedDrawScope.drawSpark(spark: Spark) {
+ with(spark) {
+ if (lifetime < 0) return
+ when (style) {
+ Spark.Style.LINE ->
+ if (opos != Vec2.Zero) drawLine(color, opos, pos, strokeWidth = size)
+ Spark.Style.LINE_ABSOLUTE ->
+ if (opos != Vec2.Zero) drawLine(color, opos, pos, strokeWidth = size / zoom)
+ Spark.Style.DOT -> drawCircle(color, size, pos)
+ Spark.Style.DOT_ABSOLUTE -> drawCircle(color, size, pos / zoom)
+ Spark.Style.RING -> drawCircle(color, size, pos, style = Stroke(width = 1f / zoom))
+ // drawPoints(listOf(pos), PointMode.Points, color, strokeWidth = 2f/zoom)
+ // drawCircle(color, 2f/zoom, pos)
+ }
+ // drawCircle(Color.Gray, center = pos, radius = 1.5f / zoom)
+ }
+}
+
+fun ZoomedDrawScope.drawTrack(track: Track) {
+ with(track) {
+ if (SIMPLE_TRACK_DRAWING) {
+ drawPoints(
+ positions,
+ pointMode = PointMode.Lines,
+ color = Color.Green,
+ strokeWidth = 1f / zoom
+ )
+ // if (positions.size < 2) return
+ // drawPath(Path()
+ // .apply {
+ // val p = positions[positions.size - 1]
+ // moveTo(p.x, p.y)
+ // positions.reversed().subList(1, positions.size).forEach { p ->
+ // lineTo(p.x, p.y)
+ // }
+ // },
+ // color = Color.Green, style = Stroke(1f/zoom))
+ } else {
+ if (positions.size < 2) return
+ var prev: Vec2 = positions[positions.size - 1]
+ var a = 0.5f
+ positions.reversed().subList(1, positions.size).forEach { pos ->
+ drawLine(Color(0f, 1f, 0f, a), prev, pos, strokeWidth = max(1f, 1f / zoom))
+ prev = pos
+ a = clamp((a - 1f / TRACK_LENGTH), 0f, 1f)
+ }
+ }
+ }
+}
diff --git a/packages/ExternalStorageProvider/res/values-bs/strings.xml b/packages/ExternalStorageProvider/res/values-bs/strings.xml
index 2c42df7..9abfcec 100644
--- a/packages/ExternalStorageProvider/res/values-bs/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bs/strings.xml
@@ -18,6 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="748293919008814871">"Aplikacija za vanjsku pohranu"</string>
<string name="storage_description" msgid="9176081505553938524">"Lokalna pohrana"</string>
- <string name="root_internal_storage" msgid="4980477711224234931">"Interna pohrana"</string>
+ <string name="root_internal_storage" msgid="4980477711224234931">"Unutrašnja pohrana"</string>
<string name="root_documents" msgid="5695037589229175941">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-te/strings.xml b/packages/ExternalStorageProvider/res/values-te/strings.xml
index 773ae0e..33a57b0 100644
--- a/packages/ExternalStorageProvider/res/values-te/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-te/strings.xml
@@ -16,8 +16,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="748293919008814871">"బాహ్య నిల్వ"</string>
- <string name="storage_description" msgid="9176081505553938524">"స్థానిక నిల్వ"</string>
- <string name="root_internal_storage" msgid="4980477711224234931">"అంతర్గత నిల్వ"</string>
- <string name="root_documents" msgid="5695037589229175941">"పత్రాలు"</string>
+ <string name="app_label" msgid="748293919008814871">"బాహ్య స్టోరేజ్"</string>
+ <string name="storage_description" msgid="9176081505553938524">"స్థానిక స్టోరేజ్"</string>
+ <string name="root_internal_storage" msgid="4980477711224234931">"అంతర్గత స్టోరేజ్"</string>
+ <string name="root_documents" msgid="5695037589229175941">"డాక్యుమెంట్లు"</string>
</resources>
diff --git a/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml b/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml
index 3ced1db..4ff09ad 100644
--- a/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml
+++ b/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml
@@ -21,13 +21,13 @@
android:layout_height="wrap_content"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollIndicators="top|bottom"
- android:fillViewport="true"
- style="?android:attr/buttonBarStyle">
+ android:fillViewport="true">
<com.android.packageinstaller.ButtonBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:orientation="horizontal"
+ style="?android:attr/buttonBarStyle"
android:gravity="start">
<Button
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 778bdfe..8a5738e 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Program geïnstalleer."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil jy hierdie program installeer?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil jy hierdie program opdateer?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Dateer hierdie app vanaf <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> op?\n\nHierdie app kry gewoonlik opdaterings vanaf <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou foon kry. Appfunksie kan verander."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Dateer hierdie app op vanaf <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Hierdie app ontvang gewoonlik opdaterings vanaf <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou tablet kry. Appfunksies kan verander.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Dateer hierdie app op vanaf <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Hierdie app ontvang gewoonlik opdaterings vanaf <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou TV kry. Appfunksies kan verander.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Dateer hierdie app op vanaf <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Hierdie app ontvang gewoonlik opdaterings vanaf <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou foon kry. Appfunksies kan verander.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Program nie geïnstalleer nie."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die installering van die pakket is geblokkeer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Program is nie geïnstalleer nie omdat pakket met \'n bestaande pakket bots."</string>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index dcc6a92..cc87288 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"መተግበሪያ ተጭኗል።"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ይህን መተግበሪያ መጫን ይፈልጋሉ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ይህን መተግበሪያ ማዘመን ይፈልጋሉ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ይህ መተግበሪያ ከ<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ይዘምን?\n\nይህ መተግበሪያ በመደበኛነት ዝማኔዎችን ከ<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ይቀበላል። ከተለየ ምንጭ በማዘመን በስልክዎ ላይ ካለ ማንኛውም ምንጭ የወደፊት ዝማኔዎችን ሊቀበሉ ይችላሉ። የመተግበሪያ ተግባራዊነት ሊለወጥ ይችላል።"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"መተግበሪያ አልተጫነም።"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ጥቅሉ እንዳይጫን ታግዷል።"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"እንደ ጥቅል ያልተጫነ መተግበሪያ ከነባር ጥቅል ጋር ይጋጫል።"</string>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index 57e0206..d501ae6 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"تم تثبيت التطبيق."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"هل تريد تثبيت هذا التطبيق؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"هل تريد تحديث هذا التطبيق؟"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"هل تريد تحديث هذا التطبيق من خلال \"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>\"؟\n\nيتلقّى هذا التطبيق التحديثات عادةً من \"<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>\". من خلال إجراء التحديث من مصدر مختلف، قد تتلقّى تحديثات في المستقبل من أي مصدر على هاتفك. قد تتغير وظائف التطبيق."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"التطبيق ليس مثبتًا."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"تم حظر تثبيت الحزمة."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"لم يتم تثبيت التطبيق لأن حزمة التثبيت تتعارض مع حزمة حالية."</string>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index a7957f5..65f6641 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"এপ্ ইনষ্টল কৰা হ’ল।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপুনি এই এপ্টো ইনষ্টল কৰিবলৈ বিচাৰেনে?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপুনি এই এপ্টো আপডে’ট কৰিবলৈ বিচাৰেনে?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"এই এপ্টো <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ৰ পৰা আপডে’ট কৰিবনে?\n\nএই এপ্টোৱে সাধাৰণতে <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ ফ’নত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>ৰ পৰা এই এপ্টো আপডে’ট কৰিবনে?</p><p>এই এপ্টোৱে সাধাৰণতে <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ টেবলেটত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>ৰ পৰা এই এপ্টো আপডে’ট কৰিবনে?</p><p>এই এপ্টোৱে সাধাৰণতে <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ টিভিত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>ৰ পৰা এই এপ্টো আপডে’ট কৰিবনে?</p><p>এই এপ্টোৱে সাধাৰণতে <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ ফ’নত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"এপ্ ইনষ্টল কৰা হোৱা নাই।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"পেকেজটোৰ ইনষ্টল অৱৰোধ কৰা হৈছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"এপ্টো ইনষ্টল কৰিব পৰা নগ\'ল কাৰণ ইয়াৰ সৈতে আগৰে পৰা থকা এটা পেকেজৰ সংঘাত হৈছে।"</string>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index ee6ace8..ca14f0d 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Tətbiq quraşdırılıb."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu tətbiqi quraşdırmaq istəyirsiniz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu tətbiqi güncəlləmək istəyirsiniz?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu tətbiq <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> mənbəyindən güncəllənsin?\n\nBu tətbiq adətən <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> mənbəyindən güncəllənmələr qəbul edir. Fərqli mənbədən güncəllədikdə telefonda istənilən mənbədən gələcəkdə güncəllənmələr qəbul edə bilərsiniz. Tətbiq funksionallığı dəyişə bilər."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Tətbiq quraşdırılmayıb."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin quraşdırılması blok edildi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Bu paketin mövcud paket ilə ziddiyətinə görə tətbiq quraşdırılmadı."</string>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index e267132..77fe3ba 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite da instalirate ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite da ažurirate ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite da ažurirate ovu aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija se obično ažurira iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na telefonu. Funkcije aplikacije mogu da se promene."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Ažurirajte ovu aplikaciju kod: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ova aplikacija obično dobija ažuriranja od: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na tabletu. Funkcije aplikacije će se možda promeniti.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Ažurirajte ovu aplikaciju kod: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ova aplikacija obično dobija ažuriranja od: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na TV-u. Funkcije aplikacije će se možda promeniti.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Ažurirajte ovu aplikaciju kod: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ova aplikacija obično dobija ažuriranja od: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na telefonu. Funkcije aplikacije će se možda promeniti.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer je paket neusaglašen sa postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index 70d2995..7b150ae 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Праграма ўсталявана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Усталяваць гэту праграму?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Абнавіць гэту праграму?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Абнавіць праграму ад <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗвычайна гэтая праграма атрымлівае абнаўленні ад <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Пры абнаўленні з іншай крыніцы вы, магчыма, будзеце атрымліваць будучыя абнаўленні з любой крыніцы на тэлефоне. Функцыі праграмы могуць змяніцца."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Праграма не ўсталявана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Усталяванне пакета заблакіравана."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Праграма не ўсталявана, таму што пакет канфліктуе з існуючым пакетам."</string>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index b3f9629..24ccfcc 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Приложението бе инсталирано."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Искате ли да инсталирате това приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Искате ли да актуализирате това приложение?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Да се актуализира ли това приложение от <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nТо обикновено получава актуализации от <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако инсталирате актуализация от друг източник, може да получавате бъдещи актуализации от който и да е източник на телефона си. Функционалността на приложението може да се промени."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Приложението не бе инсталирано."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирането на пакета бе блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложението не бе инсталирано, тъй като пакетът е в конфликт със съществуващ пакет."</string>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 5be4f7a..36fdbe8 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"অ্যাপটি ইনস্টল করা হয়ে গেছে।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপনি কি এই অ্যাপটি ইনস্টল করতে চান?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপনি কি এই অ্যাপটি আপডেট করতে চান?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> থেকে এই অ্যাপ আপডেট করবেন?\n\nএই অ্যাপ সাধারণত <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> থেকে আপডেট পায়। অন্য কোনও সোর্স থেকে আপডেট করলে, আপনার ফোনে ভবিষ্যতে যেকোনও সোর্স থেকে আপডেট পেতে পারেন। অ্যাপের কার্যকারিতা পরিবর্তন হতে পারে।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"অ্যাপটি ইনস্টল করা হয়নি।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ইনস্টল হওয়া থেকে প্যাকেজটিকে ব্লক করা হয়েছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"আগে থেকেই থাকা একটি প্যাকেজের সাথে প্যাকেজটির সমস্যা সৃষ্টি হওয়ায় অ্যাপটি ইনস্টল করা যায়নি।"</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index 2bf85c7..db6628c 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Ažurirati aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate iz drugog izvora, možda ćete primati buduća ažuriranja iz bilo kojeg izvora na telefonu. Funkcionalnost aplikacije se može promijeniti."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje ovog paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer paket nije usaglašen s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 6df1490..1750b5e 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"S\'ha instal·lat l\'aplicació."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vols instal·lar aquesta aplicació?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vols actualitzar aquesta aplicació?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vols actualitzar l\'aplicació des de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAquesta aplicació sol rebre actualitzacions a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si l\'actualitzes des d\'una font diferent, pot ser que en el futur rebis actualitzacions des de qualsevol font del teu telèfon. És possible que la funcionalitat de l\'aplicació canviï."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"No s\'ha instal·lat l\'aplicació."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"El paquet s\'ha bloquejat perquè no es pugui instal·lar."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'aplicació no s\'ha instal·lat perquè el paquet entra en conflicte amb un d\'existent."</string>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index f602bf6..47b8703 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikace je nainstalována."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete tuto aplikaci nainstalovat?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete tuto aplikaci aktualizovat?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Aktualizovat tuto aplikaci ze zdroje <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTato aplikace obvykle dostává aktualizace ze zdroje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Pokud ji aktualizujete z jiného zdroje, budete v budoucnu do telefonu moci dostávat aktualizace z libovolného zdroje. Funkčnost aplikace se může změnit."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikaci nelze nainstalovat."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalace balíčku byla zablokována."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikaci nelze nainstalovat, protože balíček je v konfliktu se stávajícím balíčkem."</string>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 04007bf..505afd6 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installeret."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du opdatere denne app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vil du opdatere denne app fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne app plejer at modtage opdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Appfunktionaliteten kan ændre sig."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Appen blev ikke installeret."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken blev forhindret i at blive installeret."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen blev ikke installeret, da pakken er i strid med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index 48f7cda..5bba467 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"App wurde installiert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Möchtest du diese App installieren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Möchtest du diese App aktualisieren?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Diese App mit einem Update von <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> aktualisieren?\n\nSie erhält normalerweise Updates von <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Wenn du ein Update von einer anderen Quelle verwendest, erhältst du möglicherweise zukünftige Updates von beliebigen Quellen auf deinem Smartphone. Die Funktionalität der App kann sich ändern."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"App wurde nicht installiert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die Installation des Pakets wurde blockiert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Die App wurde nicht installiert, da das Paket in Konflikt mit einem bestehenden Paket steht."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 54e282c..0df682c 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Η εφαρμογή εγκαταστάθηκε."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτήν την εφαρμογή;"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτήν την εφαρμογή;"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Να ενημερωθεί αυτή η εφαρμογή από <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>;\n\nΗ συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Η εφαρμογή δεν εγκαταστάθηκε."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Η εγκατάσταση του πακέτου αποκλείστηκε."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Η εφαρμογή δεν εγκαταστάθηκε, επειδή το πακέτο είναι σε διένεξη με κάποιο υπάρχον πακέτο."</string>
diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml
index 6927c3e..08b8bf1a 100644
--- a/packages/PackageInstaller/res/values-en-rAU/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rCA/strings.xml b/packages/PackageInstaller/res/values-en-rCA/strings.xml
index 03c0c27..da4a8a0 100644
--- a/packages/PackageInstaller/res/values-en-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rCA/strings.xml
@@ -26,9 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="738046584021528374">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change."</string>
- <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="3056133099508550163">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change."</string>
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml
index 6927c3e..08b8bf1a 100644
--- a/packages/PackageInstaller/res/values-en-rGB/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml
index 6927c3e..08b8bf1a 100644
--- a/packages/PackageInstaller/res/values-en-rIN/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rXC/strings.xml b/packages/PackageInstaller/res/values-en-rXC/strings.xml
index c36b3e9..0749a27 100644
--- a/packages/PackageInstaller/res/values-en-rXC/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rXC/strings.xml
@@ -26,9 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="738046584021528374">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change."</string>
- <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="3056133099508550163">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change."</string>
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Update this app from <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>This app normally receives updates from <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index c41dfb6..cc723e4 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Se instaló la app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Deseas instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Deseas actualizar esta app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"¿Quieres actualizar esta app a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEn general, esta suele recibir actualizaciones de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Por ende, podría verse afectada la funcionalidad de la app."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"No se instaló la app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se bloqueó el paquete para impedir la instalación."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"No se instaló la app debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 7fdf346..0a85d78 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplicación instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Quieres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Quieres actualizar esta aplicación?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"¿Actualizar esta aplicación a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEsta aplicación normalmente recibe actualizaciones a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si la actualizas usando otra fuente, puede que recibas futuras actualizaciones a través de cualquier fuente en tu teléfono. La funcionalidad de la aplicación puede cambiar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"No se ha instalado la aplicación."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se ha bloqueado la instalación del paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"La aplicación no se ha instalado debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index 7f3c4a5..9cb4be7 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Rakendus on installitud."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Kas soovite selle rakenduse installida?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Kas soovite seda rakendust värskendada?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Kas värskendada seda rakendust allikast <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nSee rakendus saab tavaliselt värskendusi allikast <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Muust allikast värskendamise korral võite edaspidi saada telefonis värskendusi mis tahes allikast. Rakenduse funktsioonid võivad muutuda."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Rakendus pole installitud."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketi installimine blokeeriti."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Rakendust ei installitud, kuna pakett on olemasoleva paketiga vastuolus."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index e446d47..cd443a7 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Instalatu da aplikazioa."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Aplikazioa instalatu nahi duzu?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Aplikazioa eguneratu nahi duzu?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Aplikazioa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> zerbitzutik eguneratu nahi duzu?\n\nAplikazioak <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> zerbitzutik jaso ohi ditu eguneratzeak. Beste iturburu batetik eguneratuz gero, baliteke aurrerantzeko eguneratzeak telefonoko edozein iturburutatik jasotzea. Baliteke aplikazioaren funtzioak aldatzea."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Ez da instalatu aplikazioa."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketea instalatzeko aukera blokeatu egin da."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Ez da instalatu aplikazioa, gatazka bat sortu delako lehendik dagoen pakete batekin."</string>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index b2d3d76..bbd984f 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"برنامه نصب شد."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"میخواهید این برنامه را نصب کنید؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"میخواهید این برنامه را بهروزرسانی کنید؟"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"این برنامه ازطریق <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> بهروز شود؟\n\nاین برنامه معمولاً بهروزرسانیها را از <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> دریافت میکند. با بهروزرسانی از منبعی متفاوت، ممکن است بهروزرسانیهای بعدی را از هر منبعی در تلفنتان دریافت کنید. قابلیتهای برنامه ممکن است تغییر کند."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"برنامه نصب نشد."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"از نصب شدن بسته جلوگیری شد."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"برنامه نصب نشد چون بسته با بسته موجود تداخل دارد."</string>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index 6c63e4b..f73fdb2 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Sovellus on asennettu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Haluatko asentaa tämän sovelluksen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Haluatko päivittää tämän sovelluksen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Voiko <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> päivittää sovelluksen?\n\nTämän sovelluksen päivitykset tarjoaa yleensä <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kun päivität uudesta lähteestä, tulevat päivitykset voivat tulla mistä tahansa puhelimella olevasta lähteestä. Sovelluksen toiminnot voivat muuttua."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Sovellusta ei asennettu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin asennus estettiin."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Sovellusta ei asennettu, koska paketti on ristiriidassa nykyisen paketin kanssa."</string>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 9b82fd4..40c4649 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette application?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette application?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Mettre à jour cette application à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nCette application reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut en être modifié."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du paquet a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 2fc5e53..df2e007 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Mettre à jour cette appli à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ?\n\nCette appli reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application est susceptible de changer."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du package a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le package est en conflit avec un package déjà présent."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index 39bab7a..55512cf 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Queres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Queres actualizar esta aplicación?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Queres actualizar esta aplicación desde <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs actualizacións desta aplicación adoitan provir de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se actualizas a aplicación desde unha fonte diferente, pode que, a partir de agora, recibas actualizacións de calquera fonte no teléfono. Poderían cambiar as funcións da aplicación."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Non se instalou a aplicación"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Bloqueouse a instalación do paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A aplicación non se instalou porque o paquete presenta un conflito cun paquete que xa hai."</string>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index 1793887..8f5976c 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"શું તમે આ ઍપ ઇન્સ્ટૉલ કરવા માગો છો?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"શું તમે આ ઍપ અપડેટ કરવા માગો છો?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"આ ઍપને <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>થી અપડેટ કરવી છે?\n\nઆ ઍપ સામાન્ય રીતે <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ફોન પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતા બદલાઈ શકે છે."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>શું આ ઍપને <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>થી અપડેટ કરવી છે?</p><p>આ ઍપ સામાન્ય રીતે <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ટૅબ્લેટ પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતામાં ફેરફાર થઈ શકે.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>શું આ ઍપને <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>થી અપડેટ કરવી છે?</p><p>આ ઍપ સામાન્ય રીતે <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ટીવી પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતામાં ફેરફાર થઈ શકે.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>શું આ ઍપને <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>થી અપડેટ કરવી છે?</p><p>આ ઍપ સામાન્ય રીતે <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ફોન પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતામાં ફેરફાર થઈ શકે.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી નથી."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"પૅકેજને ઇન્સ્ટૉલ થવાથી બ્લૉક કરવામાં આવ્યું હતું."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"પૅકેજનો અસ્તિત્વમાંના પૅકેજ સાથે વિરોધાભાસ હોવાને કારણે ઍપ્લિકેશન ઇન્સ્ટૉલ થઈ નથી."</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index cfcec76..930757b 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ऐप्लिकेशन इंस्टॉल हो गया."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"क्या आपको यह ऐप्लिकेशन इंस्टॉल करना है?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"क्या आप इस ऐप्लिकेशन को अपडेट करना चाहते हैं?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"क्या इस ऐप्लिकेशन को <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> से अपडेट करना है?\n\nआम तौर पर, इस ऐप्लिकेशन को <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> से अपडेट मिलते हैं. किसी दूसरे सोर्स से अपडेट करने पर, आपको नए अपडेट फ़ोन पर मौजूद किसी भी सोर्स से मिल सकते हैं. इसके साथ ही, ऐप्लिकेशन की मुख्य सुविधाओं और उनके काम करने के तरीके में बदलाव आ सकता है."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ऐप्लिकेशन इंस्टॉल नहीं हुआ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पैकेज को इंस्टॉल होने से ब्लॉक किया हुआ है."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ऐप्लिकेशन इंस्टॉल नहीं हुआ क्योंकि पैकेज का किसी मौजूदा पैकेज से विरोध है."</string>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index a7621dd..0977745 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite li ovu aplikaciju ažurirati s izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja s izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate s nekog drugog izvora, buduća ažuriranja možete primati s bilo kojeg izvora na svojem telefonu. Funkcije aplikacije mogu se promijeniti."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa blokirano je."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija koja nije instalirana kao paket u sukobu je s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index b02b4aa..022f6456 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Alkalmazás telepítve."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Telepíti ezt az alkalmazást?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Frissíti ezt az alkalmazást?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Frissíti az appot ebből a forrásból: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEz az app általában a következő forrásból kap frissítéseket: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ha másik forrásból frissíti, a későbbiekben bármelyik forrásból kaphat frissítéseket a telefonján. Emiatt megváltozhat az app működése."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Az alkalmazás nincs telepítve."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A csomag telepítését letiltotta a rendszer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A nem csomagként telepített alkalmazás ütközik egy már létező csomaggal."</string>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index 48a10e8..6eba377 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Հավելվածը տեղադրված է:"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Տեղադրե՞լ այս հավելվածը:"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Թարմացնե՞լ այս հավելվածը։"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Թարմացնե՞լ այս հավելվածը <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ից։\n\nՍովորաբար այս հավելվածի թարմացումները ստացվում են <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ից։ Եթե թարմացնեք այլ աղբյուրից, հետագայում կարող եք ձեր հեռախոսում թարմացումներ ստանալ ցանկացած աղբյուրից։ Հավելվածի գործառույթները կարող են փոփոխվել։"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Հավելվածը տեղադրված չէ:"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Փաթեթի տեղադրումն արգելափակվել է:"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Հավելվածը չի տեղադրվել, քանի որ տեղադրման փաթեթն ունի հակասություն առկա փաթեթի հետ:"</string>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index f204419..726a306 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi terinstal."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingin menginstal aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingin mengupdate aplikasi ini?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update aplikasi ini dari <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAplikasi ini biasanya menerima update dari <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan mengupdate dari sumber yang berbeda, Anda mungkin menerima update berikutnya dari sumber mana pun di ponsel. Fungsi aplikasi mungkin berubah."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak terinstal."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paket diblokir sehingga tidak dapat diinstal."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikasi tidak diinstal karena paket ini bentrok dengan paket yang sudah ada."</string>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index 94dc375..4388f1c 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Forritið er uppsett."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Viltu setja upp þetta forrit?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Viltu uppfæra þetta forrit?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Uppfæra þetta forrit frá <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nÞetta forrit fær venjulega uppfærslur frá <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Með því að uppfæra frá öðrum uppruna gætirðu fengið framtíðaruppfærslur frá hvaða uppruna sem er í símanum. Forritseiginleikar kunna að breytast."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Forritið er ekki uppsett."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Lokað var á uppsetningu pakkans."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Forritið var ekki sett upp vegna árekstra á milli pakkans og annars pakka."</string>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 0f97d54..03e3925 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installata."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vuoi installare questa app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vuoi aggiornare questa app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vuoi aggiornare questa app tramite <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nGeneralmente l\'app viene aggiornata tramite <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sul telefono. La funzionalità dell\'app potrebbe cambiare."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Vuoi aggiornare questa app da <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Generalmente l\'app riceve gli aggiornamenti da <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sul tablet. La funzionalità dell\'app potrebbe cambiare.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Vuoi aggiornare questa app da <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Generalmente l\'app riceve gli aggiornamenti da <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sulla TV. La funzionalità dell\'app potrebbe cambiare.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Vuoi aggiornare questa app da <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Generalmente l\'app riceve gli aggiornamenti da <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sullo smartphone. La funzionalità dell\'app potrebbe cambiare.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"App non installata."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"È stata bloccata l\'installazione del pacchetto."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App non installata poiché il pacchetto è in conflitto con un pacchetto esistente."</string>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 0f0c029..6684ec0 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"האפליקציה הותקנה."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"האם ברצונך להתקין אפליקציה זו?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"האם ברצונך לעדכן אפליקציה זו?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"לקבל את העדכון לאפליקציה הזו מ-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nהאפליקציה הזו בדרך כלל מקבלת עדכונים מ: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלפון. תכונות האפליקציה יכולות להשתנות."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>לקבל את העדכון לאפליקציה הזו מ-<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>האפליקציה הזו בדרך כלל מקבלת עדכונים מ-<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטאבלט. תכונות האפליקציה עשויות להשתנות.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>לקבל את העדכון לאפליקציה הזו מ-<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>האפליקציה הזו בדרך כלל מקבלת עדכונים מ-<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלוויזיה. תכונות האפליקציה עשויות להשתנות.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>לקבל את העדכון לאפליקציה הזו מ-<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>האפליקציה הזו בדרך כלל מקבלת עדכונים מ-<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלפון. תכונות האפליקציה עשויות להשתנות.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"האפליקציה לא הותקנה."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"החבילה נחסמה להתקנה."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"האפליקציה לא הותקנה כי החבילה מתנגשת עם חבילה קיימת."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index b045ed5..600b6b7 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"アプリをインストールしました。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"このアプリをインストールしますか?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"このアプリを更新しますか?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"このアプリを <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> から更新しますか?\n\nこのアプリは通常、<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> からアップデートを受信しています。別の提供元から更新することにより、お使いのスマートフォンで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>このアプリを <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> から更新しますか?</p><p>このアプリは通常、<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> からアップデートを受信しています。別の提供元から更新することにより、お使いのタブレットで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>このアプリを <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> から更新しますか?</p><p>このアプリは通常、<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> からアップデートを受信しています。別の提供元から更新することにより、お使いのテレビで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>このアプリを <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> から更新しますか?</p><p>このアプリは通常、<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> からアップデートを受信しています。別の提供元から更新することにより、お使いのスマートフォンで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"アプリはインストールされていません。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"パッケージのインストールはブロックされています。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"パッケージが既存のパッケージと競合するため、アプリをインストールできませんでした。"</string>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index b0b1162..c8bf93b 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"აპი დაინსტალირებულია."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"გნებავთ ამ აპის დაყენება?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"გსურთ ამ აპის განახლება?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"გსურთ განაახლოთ ეს აპი <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ისგან?\n\nეს აპი, როგორც წესი, განახლებებს იღებს <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ისგან. აპის სხვა წყაროდან განახლებით შემდგომში განახლებების მიღებას შეძლებთ ნებისმიერი წყაროდან თქვენს ტელეფონზე. აპის ფუნქციები, შესაძლოა, შეიცვალოს."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>გსურთ განაახლოთ ეს აპი <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>-ისგან?</p><p>ეს აპი ჩვეულებრივ განახლებებს იღებს <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>-ისგან. სხვა წყაროდან განახლებით, შეგიძლიათ მიიღოთ მომავალი განახლებები ტაბლეტზე არსებული ნებისმიერი წყაროდან. აპის ფუნქციები შეიძლება შეიცვალოს.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>გსურთ განაახლოთ ეს აპი <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>-ისგან?</p><p>ეს აპი ჩვეულებრივ განახლებებს იღებს <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>-ისგან. სხვა წყაროდან განახლებით, შეგიძლიათ მიიღოთ მომავალი განახლებები ტელევიზორზე არსებული ნებისმიერი წყაროდან. აპის ფუნქციები შეიძლება შეიცვალოს.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>გსურთ განაახლოთ ეს აპი <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>-ისგან?</p><p>ეს აპი ჩვეულებრივ განახლებებს იღებს <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>-ისგან. აპის სხვა წყაროდან განახლებით შემდგომში განახლებების მიღებას შეძლებთ ნებისმიერი წყაროდან თქვენს ტელეფონზე. აპის ფუნქციები შეიძლება შეიცვალოს.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"აპი დაუინსტალირებელია."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ამ პაკეტის ინსტალაცია დაბლოკილია."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"აპი ვერ დაინსტალირდა, რადგან პაკეტი კონფლიქტშია არსებულ პაკეტთან."</string>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index 2011b80..1831b00 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Қолданба орнатылды."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бұл қолданбаны орнатқыңыз келе ме?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бұл қолданбаны жаңартқыңыз келе ме?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Бұл қолданба <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> арқылы жаңартылсын ба?\n\nБұл қолданба әдетте <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> көмегімен жаңартылады. Басқа дереккөзден жаңартсаңыз, алдағы жаңартулар телефоныңыздағы кез келген дереккөзден келуі мүмкін. Қолданба функциялары өзгеруі мүмкін."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Қолданба орнатылмады."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Пакетті орнатуға тыйым салынды."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Жаңа пакет пен бұрыннан бар пакеттің арасында қайшылық туындағандықтан, қолданба орнатылмады."</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 4a221ac..3e3ef99 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"បានដំឡើងកម្មវិធី។"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"តើអ្នកចង់ដំឡើងកម្មវិធីនេះដែរទេ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"តើអ្នកចង់ដំឡើងកំណែកម្មវិធីនេះដែរទេ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ដំឡើងកំណែកម្មវិធីនេះពី <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ឬ?\n\nកម្មវិធីនេះជាធម្មតាទទួលបានកំណែថ្មីពី <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចនឹងទទួលបានកំណែថ្មីនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរសព្ទរបស់អ្នក។ មុខងារកម្មវិធីអាចមានការផ្លាស់ប្ដូរ។"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>ដំឡើងកំណែកម្មវិធីនេះពី <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ឬ?</p><p>ជាធម្មតា កម្មវិធីនេះទទួលបានកំណែថ្មីពី <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចទទួលបានកំណែថ្មីៗនាពេលអនាគតពីប្រភពណាក៏បាននៅលើថេប្លេតរបស់អ្នក។ មុខងារកម្មវិធីអាចផ្លាស់ប្ដូរ។</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>ដំឡើងកំណែកម្មវិធីនេះពី <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ឬ?</p><p>ជាធម្មតា កម្មវិធីនេះទទួលបានកំណែថ្មីពី <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចទទួលបានកំណែថ្មីៗនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរទស្សន៍របស់អ្នក។ មុខងារកម្មវិធីអាចផ្លាស់ប្ដូរ។</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>ដំឡើងកំណែកម្មវិធីនេះពី <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ឬ?</p><p>ជាធម្មតា កម្មវិធីនេះទទួលបានកំណែថ្មីពី <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចនឹងទទួលបានកំណែថ្មីនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរសព្ទរបស់អ្នក។ មុខងារកម្មវិធីអាចផ្លាស់ប្ដូរ។</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"មិនបានដំឡើងកម្មវិធីទេ។"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"កញ្ចប់ត្រូវបានទប់ស្កាត់មិនឱ្យដំឡើង។"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"កម្មវិធីមិនបានដំឡើងទេ ដោយសារកញ្ចប់កម្មវិធីមិនត្រូវគ្នាជាមួយកញ្ចប់ដែលមានស្រាប់។"</string>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 861e73e..2cbbc08 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕೇ?\n\nಈ ಆ್ಯಪ್ ಸಾಮಾನ್ಯವಾಗಿ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ನಿಂದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಸ್ವೀಕರಿಸುತ್ತದೆ. ಬೇರೆ ಮೂಲವೊಂದರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿರುವ ಯಾವುದೇ ಮೂಲದಿಂದ ಭವಿಷ್ಯದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ನೀವು ಸ್ವೀಕರಿಸಬಹುದು. ಆ್ಯಪ್ನ ಕಾರ್ಯಚಟುವಟಿಕೆಯು ಬದಲಾಗಬಹುದು."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿಲ್ಲ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ಪ್ಯಾಕೇಜ್ನಂತೆ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿರುವ ಆ್ಯಪ್ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೇಜ್ ಜೊತೆಗೆ ಸಂಘರ್ಷವಾಗುತ್ತದೆ."</string>
@@ -102,7 +103,7 @@
<string name="anonymous_source_continue" msgid="4375745439457209366">"ಮುಂದುವರಿಸಿ"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"wear ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್/ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿರುವ ಕುರಿತು ಅಧಿಸೂಚನೆ"</string>
+ <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿರುವ ಕುರಿತು ನೋಟಿಫಿಕೇಶನ್"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"ಯಶಸ್ವಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಆಗಿದೆ"</string>
<string name="notification_installation_success_status" msgid="3172502643504323321">"\"<xliff:g id="APPNAME">%1$s</xliff:g>\" ಆ್ಯಪ್ ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index c51e507..a36780d 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"앱이 설치되었습니다."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"이 앱을 설치하시겠습니까?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"이 앱을 업데이트하시겠습니까?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서 이 앱에 대한 업데이트를 받으시겠습니까?\n\n평소에는 <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>에서 앱을 업데이트했습니다. 다른 출처에서 앱을 업데이트하면 향후 휴대전화에 있는 어떤 출처에서든지 업데이트를 받을 수 있습니다. 앱 기능도 변경될 수 있습니다."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"앱이 설치되지 않았습니다."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"패키지 설치가 차단되었습니다."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"패키지가 기존 패키지와 충돌하여 앱이 설치되지 않았습니다."</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index 5821c82..5a6ed45 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Колдонмо орнотулду."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бул колдонмону орнотоюн деп жатасызбы?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бул колдонмону жаңыртайын деп жатасызбы?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Колдонмону <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> аркылуу жаңыртасызбы?\n\nАдатта бул колдонмонун жаңыртууларын <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> жөнөтөт. Эгер колдонмону башка булактан жаңыртсаңыз, эртеңки күнү телефонуңуз ар кайсы булактан жаңырып, колдонмонун функциялары өзгөрүшү мүмкүн."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Колдонмо орнотулган жок."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Топтомду орнотууга болбойт."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Башка топтом менен дал келбегендиктен колдонмо орнотулган жок."</string>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index 9e609f2..81f89d9 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ຕິດຕັ້ງແອັບແລ້ວ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ທ່ານຕ້ອງການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ທ່ານຕ້ອງການອັບເດດແອັບນີ້ບໍ່?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ອັບເດດແອັບນີ້ຈາກ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ບໍ?\n\nໂດຍທົ່ວໄປແລ້ວແອັບນີ້ຈະໄດ້ຮັບການອັບເດດຈາກ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. ການອັບເດດຈາກແຫຼ່ງທີ່ມາອື່ນອາດເຮັດໃຫ້ໂທລະສັບຂອງທ່ານໄດ້ຮັບການອັບເດດຈາກແຫຼ່ງທີ່ມານັ້ນໃນອະນາຄົດ. ຟັງຊັນການເຮັດວຽກຂອງແອັບອາດມີການປ່ຽນແປງ."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເທື່ອ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ແພັກເກດຖືກບລັອກບໍ່ໃຫ້ໄດ້ຮັບການຕິດຕັ້ງ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເນື່ອງຈາກແພັກເກດຂັດແຍ່ງກັບແພັກເກດທີ່ມີຢູ່ກ່ອນແລ້ວ."</string>
diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml
index 1ee6f05..94cf2d8 100644
--- a/packages/PackageInstaller/res/values-lt/strings.xml
+++ b/packages/PackageInstaller/res/values-lt/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Programa įdiegta."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ar norite įdiegti šią programą?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ar norite atnaujinti šią programą?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atnaujinti šią programą iš <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nŠi programa įprastai gauna naujinius iš <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Atnaujinę iš kito šaltinio, būsimus naujinius galite gauti iš bet kurio šaltinio telefone. Gali būti pakeistos programos funkcijos."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Programa neįdiegta."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketas užblokuotas ir negali būti įdiegtas."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Programa neįdiegta, nes paketas nesuderinamas su esamu paketu."</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index dfb4399..e85ac80 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Lietotne ir instalēta."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vai vēlaties instalēt šo lietotni?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vai vēlaties atjaunināt šo lietotni?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vai atjaunināt šo lietotni, izmantojot “<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>”?\n\nŠī lietotne parasti saņem atjauninājumus no “<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>”. Veicot atjaunināšanu no cita avota, iespējams, turpmāk tālrunī saņemsiet atjauninājumus no jebkāda avota. Lietotnes funkcionalitāte var mainīties."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Lietotne nav instalēta."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakotnes instalēšana tika bloķēta."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Lietotne netika instalēta, jo pastāv pakotnes konflikts ar esošu pakotni."</string>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index 6cd2db3..8273e78 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Апликацијата е инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Дали сакате да ја инсталирате апликацијава?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Дали сакате да ја ажурирате апликацијава?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Да се ажурира апликацијава од <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nАпликацијава вообичаено добива ажурирања од<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Со ажурирање од различен извор, може да добивате идни ажурирања од кој било извор на вашиот телефон. Функционалноста на апликацијата може да се промени."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Апликацијата не е инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирањето на пакетот е блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација што не е инсталирана како пакет е во конфликт со постоечки пакет."</string>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index 9e4e99b..a64f87f 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തു."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?\n\nഈ ആപ്പിന് സാധാരണയായി <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നത് വഴി, നിങ്ങളുടെ ഫോണിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിക്കാൻ ഇടയുണ്ട്. ആപ്പ് ഫംഗ്ഷണാലിറ്റിയിൽ വ്യത്യാസം വന്നേക്കാം."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p> <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?</p><p>ഈ ആപ്പിന് സാധാരണയായി <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നതിലൂടെ, നിങ്ങളുടെ ടാബ്ലെറ്റിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിച്ചേക്കാം. ആപ്പ് ഫംഗ്ഷണാലിറ്റി മാറിയേക്കാം.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p> <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?</p><p>ഈ ആപ്പിന് സാധാരണയായി <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നതിലൂടെ, നിങ്ങളുടെ ടിവിയിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിച്ചേക്കാം. ആപ്പ് ഫംഗ്ഷണാലിറ്റി മാറിയേക്കാം.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p> <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?</p><p>ഈ ആപ്പിന് സാധാരണയായി <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നത് വഴി, നിങ്ങളുടെ ഫോണിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിക്കാൻ ഇടയുണ്ട്. ആപ്പ് ഫംഗ്ഷണാലിറ്റി മാറിയേക്കാം.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"പാക്കേജ് ഇൻസ്റ്റാൾ ചെയ്യുന്നത് ബ്ലോക്ക് ചെയ്തു."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"പാക്കേജിന് നിലവിലുള്ള പാക്കേജുമായി പൊരുത്തക്കേടുള്ളതിനാൽ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തില്ല."</string>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index b427c85..8a86d11 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Аппыг суулгасан."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Та энэ аппыг суулгахыг хүсэж байна уу?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Та энэ аппыг шинэчлэхийг хүсэж байна уу?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Аппыг <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-с шинэчлэх үү?\n\nЭнэ апп ихэвчлэн <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-с шинэчлэлт хүлээн авдаг. Өөр эх сурвалжаас шинэчилснээр та ирээдүйн шинэчлэлтийг утсан дээрх аливаа эх сурвалжаас хүлээн авч магадгүй. Аппын ажиллагаа өөрчлөгдөж магадгүй."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Аппыг суулгаагүй."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Багц суулгахыг блоклосон байна."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Багц одоо байгаа багцтай тохирохгүй байгаа тул аппыг суулгаж чадсангүй."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 17aa8ee..81e406c 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तुम्हाला हे ॲप इंस्टॉल करायचे आहे का?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तुम्हाला हे ॲप अपडेट करायचे आहे का?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> वरून हे अॅप अपडेट करायचे आहे का?\n\nया अॅपला सामान्यतः <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> कडून अपडेट मिळतात. वेगवेगळ्या स्रोताकडून अपडेट करून, तुम्हाला तुमच्या फोनवरील कोणत्याही स्रोताकडून भविष्यातील अपडेट मिळू शकतात. अॅपची कार्यक्षमता बदलू शकते."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 9f3e55f..80f4be3 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi dipasang."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Adakah anda ingin memasang aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Adakah anda mahu mengemas kini apl ini?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Kemas kinikan apl ini daripada <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nApl ini biasanya menerima kemaskinian daripada <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada telefon anda. Fungsi apl mungkin berubah."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Kemas kinikan apl ini daripada <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Apl ini biasanya menerima kemaskinian daripada <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada tablet anda. Fungsi apl mungkin berubah.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Kemas kinikan apl ini daripada <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Apl ini biasanya menerima kemaskinian daripada <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada TV anda. Fungsi apl mungkin berubah.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Kemas kinikan apl ini daripada <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Apl ini biasanya menerima kemaskinian daripada <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada telefon anda. Fungsi apl mungkin berubah.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak dipasang."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakej ini telah disekat daripada dipasang."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Apl tidak dipasang kerana pakej bercanggah dengan pakej yang sedia ada."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index 054bf13..77a45899 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ။"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ဤအက်ပ်ကို ထည့်သွင်းလိုသလား။"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ဤအက်ပ်ကို အပ်ဒိတ်လုပ်လိုသလား။"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ဤအက်ပ်ကို <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> မှ အပ်ဒိတ်လုပ်မလား။\n\nဤအက်ပ်သည် ပုံမှန်အားဖြင့် <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် ဖုန်းပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မှမဆို လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းလဲနိုင်သည်။"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>ဤအက်ပ်ကို <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> မှ အပ်ဒိတ်လုပ်မလား။</p><p>ဤအက်ပ်သည် ပုံမှန်အားဖြင့် <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် တက်ဘလက်ပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မဆိုမှ လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းနိုင်သည်။</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>ဤအက်ပ်ကို <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> မှ အပ်ဒိတ်လုပ်မလား။</p><p>ဤအက်ပ်သည် ပုံမှန်အားဖြင့် <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် TV ပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မဆိုမှ လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းနိုင်သည်။</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>ဤအက်ပ်ကို <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> မှ အပ်ဒိတ်လုပ်မလား။</p><p>ဤအက်ပ်သည် ပုံမှန်အားဖြင့် <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် ဖုန်းပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မဆိုမှ လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းနိုင်သည်။</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"အက်ပ်မထည့်သွင်းရသေးပါ"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ပက်ကေ့ဂျ်ထည့်သွင်းခြင်းကို ပိတ်ထားသည်။"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ပက်ကေ့ဂျ်အဖြစ် ထည့်သွင်းမထားသော အက်ပ်သည် လက်ရှိပက်ကေ့ဂျ်နှင့် တိုက်နေသည်။"</string>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index 05045ab..5919ede 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du oppdatere denne appen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vil du oppdatere denne appen fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne appen mottar vanligvis oppdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du oppdaterer fra en annen kilde, kan du få fremtidige oppdateringer fra en hvilken som helst kilde på telefonen. Appfunksjonaliteten kan endres."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Appen ble ikke installert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken er blokkert fra å bli installert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen ble ikke installert fordi pakken er i konflikt med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 81e410d..603dfa2 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"एप इन्स्टल गरियो।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तपाईं यो एप इन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तपाईं यो एप अपडेट गर्न चाहनुहुन्छ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"यो एप <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> बाट अपडेट गर्ने हो?\n\nयो एपले सामान्यतया <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> बाट अपडेट प्राप्त गर्छ। तपाईंले कुनै फरक स्रोतबाट अपडेट गर्नुभयो भने तपाईं भविष्यमा आफ्नो फोनमा भएको जुनसुकै स्रोतबाट अपडेटहरू प्राप्त गर्न सक्नुहुन्छ। यसो गर्दा एपका मुख्य सुविधाहरूले काम गर्ने तरिका परिवर्तन हुन सक्छ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index c8a3e70..d38faaf 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"App geïnstalleerd."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil je deze app installeren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil je deze app updaten?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Deze app updaten via <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDeze app krijgt gewoonlijk updates via <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Als je updatet via een andere bron, kun je toekomstige updates via elke bron op je telefoon krijgen. De app-functionaliteit kan veranderen."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"App niet geïnstalleerd."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"De installatie van het pakket is geblokkeerd."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App die niet is geïnstalleerd als pakket conflicteert met een bestaand pakket."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 563e93b..8eb81e5 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="7488448184431507488">"ପ୍ୟାକେଜ୍ ଇନଷ୍ଟଲର୍"</string>
- <string name="install" msgid="711829760615509273">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="install" msgid="711829760615509273">"ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="update" msgid="3932142540719227615">"ଅପଡେଟ୍ କରନ୍ତୁ"</string>
<string name="done" msgid="6632441120016885253">"ହୋଇଗଲା"</string>
<string name="cancel" msgid="1018267193425558088">"ବାତିଲ କରନ୍ତୁ"</string>
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ଆପ ଇନଷ୍ଟଲ ହୋଇଗଲା।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ଆପଣ ଏହି ଆପକୁ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ଆପଣ ଏହି ଆପକୁ ଅପଡେଟ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ରୁ ଏହି ଆପକୁ ଅପଡେଟ କରିବେ?\n\nଏହି ଆପ ସାଧାରଣତଃ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଅପଡେଟଗୁଡ଼ିକ ପାଏ। ଏକ ଭିନ୍ନ ସୋର୍ସରୁ ଅପଡେଟ କରି ଆପଣଙ୍କ ଫୋନରେ ଯେ କୌଣସି ସୋର୍ସରୁ ଭବିଷ୍ୟତର ଅପଡେଟଗୁଡ଼ିକ ଆପଣ ପାଇପାରନ୍ତି। ଆପ କାର୍ଯ୍ୟକ୍ଷମତା ପରିବର୍ତ୍ତନ ହୋଇପାରେ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ଏହି ପ୍ୟାକେଜ୍କୁ ଇନଷ୍ଟଲ୍ କରାଯିବାରୁ ଅବରୋଧ କରାଯାଇଥିଲା।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ପୂର୍ବରୁ ଥିବା ପ୍ୟାକେଜ୍ ସହ ଏହି ପ୍ୟାକେଜ୍ର ସମସ୍ୟା ଉପୁଯିବାରୁ ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇପାରିଲା ନାହିଁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 41b1fce..78a2342 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ਐਪ ਸਥਾਪਤ ਕੀਤੀ ਗਈ।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?\n\nਇਸ ਐਪ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਹੁੰਦੀਆਂ ਹਨ। ਕਿਸੇ ਵੱਖਰੇ ਸਰੋਤ ਤੋਂ ਅੱਪਡੇਟ ਕਰ ਕੇ, ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਕਿਸੇ ਵੀ ਸਰੋਤ ਤੋਂ ਭਵਿੱਖੀ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ। ਐਪ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਬਦਲ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ਪੈਕੇਜ ਨੂੰ ਸਥਾਪਤ ਹੋਣ ਤੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ਪੈਕੇਜ ਦੇ ਇੱਕ ਮੌਜੂਦਾ ਪੈਕੇਜ ਨਾਲ ਵਿਵਾਦ ਹੋਣ ਕਰਕੇ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index 360181c..6adb37f 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacja została zainstalowana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Zainstalować tę aplikację?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Zaktualizować tę aplikację?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Zastosować do aplikacji aktualizację pochodzącą z tego źródła (<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>)?\n\nAktualizacje dla tej aplikacji zwykle dostarcza <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Jeśli zastosujesz aplikację pochodzącą z innego źródła, możesz w przyszłości otrzymywać na telefonie aktualizacje z dowolnych źródeł. Funkcje aplikacji mogą się zmienić."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikacja nie została zainstalowana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalacja pakietu została zablokowana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacja nie została zainstalowana, bo powoduje konflikt z istniejącym pakietem."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 3fca451..d4aae75 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index 8dd1b7b..cfa2ca6 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Pretende atualizar esta app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar esta app a partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNormalmente, esta app recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se atualizar a partir de uma fonte diferente, poderá receber futuras atualizações de qualquer fonte no seu telemóvel. A funcionalidade da app pode sofrer alterações."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Atualize esta app a partir do proprietário <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Normalmente, esta app recebe atualizações a partir do proprietário <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se atualizar a partir de uma origem diferente, pode receber futuras atualizações de qualquer origem no seu tablet. A funcionalidade da app pode mudar.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Atualize esta app a partir do proprietário <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Normalmente, esta app recebe atualizações a partir do proprietário <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se atualizar a partir de uma origem diferente, pode receber futuras atualizações de qualquer origem na sua TV. A funcionalidade da app pode mudar.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Atualize esta app a partir do proprietário <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Normalmente, esta app recebe atualizações a partir do proprietário <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Se atualizar a partir de uma origem diferente, pode receber futuras atualizações de qualquer origem no seu telemóvel. A funcionalidade da app pode mudar.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicação não instalada."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Foi bloqueada a instalação do pacote."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A app não foi instalada porque o pacote entra em conflito com um pacote existente."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 3fca451..d4aae75 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index a53b664..fab0c33 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Aplicație instalată."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vrei să instalezi această aplicație?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vrei să actualizezi această aplicație?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Actualizezi aplicația de la <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDe obicei, aplicația primește actualizări de la <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe telefon. Funcționalitatea aplicației se poate modifica."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Actualizează aplicația de la <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>De obicei, aplicația primește actualizări de la <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe tabletă. Funcționalitatea aplicației se poate modifica.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Actualizează aplicația de la <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>De obicei, aplicația primește actualizări de la <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe televizor. Funcționalitatea aplicației se poate modifica.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Actualizează aplicația de la <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>De obicei, aplicația primește actualizări de la <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe telefon. Funcționalitatea aplicației se poate modifica.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicația nu a fost instalată."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalarea pachetului a fost blocată."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplicația nu a fost instalată deoarece pachetul intră în conflict cu un pachet existent."</string>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index bf5cd9f..2c9888b 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Приложение установлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установить приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Обновить приложение?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Обновить приложение отсюда: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nСтандартный источник обновлений этого приложения – <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Если обновить приложение из другого источника, для последующих обновлений будут использоваться любые источники на телефоне. Функции приложения могут измениться."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Приложение не установлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Установка пакета заблокирована."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложение не установлено, так как оно конфликтует с другим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index faad85a..8486644 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"යෙදුම ස්ථාපනය කර ඇත."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"මෙම යෙදුම ස්ථාපනය කිරීමට ඔබට අවශ්යද?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ඔබට මෙම යෙදුම යාවත්කාලීන කිරීමට අවශ්යද?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> වෙතින් මෙම යෙදුම යාවත්කාලීන කරන්න ද?\n\nමෙම යෙදුමට සාමාන්යයෙන් <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> සිට යාවත්කාලීන ලැබේ. වෙනස් මූලාශ්රයකින් යාවත්කාලීන කිරීමෙන්, ඔබට ඔබේ දුරකථනයෙහි ඕනෑම මූලාශ්රයකින් අනාගත යාවත්කාලීන ලැබීමට ඉඩ ඇත. යෙදුම් ක්රියාකාරිත්වය වෙනස් වීමට ඉඩ ඇත."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"යෙදුම ස්ථාපනය කර නැත."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"මෙම පැකේජය ස්ථාපනය කිරීම අවහිර කරන ලදි."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"පැකේජය දැනට පවතින පැකේජයක් සමග ගැටෙන නිසා යෙදුම ස්ථාපනය නොකරන ලදී."</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 41ab45a..ed3ca7e 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikácia bola nainštalovaná."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete túto aplikáciu nainštalovať?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete túto aplikáciu aktualizovať?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Chcete aktualizovať túto aplikáciu zo zdroja <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTúto aplikáciu obvykle aktualizuje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ak vykonáte aktualizáciu z iného zdroja, aplikácia sa v budúcnosti môže aktualizovať z ľubovoľného zdroja v telefóne. Funkcie aplikácie sa môžu zmeniť."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikácia nebola nainštalovaná."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Inštalácia balíka bola zablokovaná."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikácia sa nenainštalovala, pretože balík je v konflikte s existujúcim balíkom."</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index e426464..91bcbda 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je nameščena."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ali želite namestiti to aplikacijo?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ali želite posodobiti to aplikacijo?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite to aplikacijo posodobiti iz vira <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTa aplikacija običajno prejema posodobitve iz vira <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v telefonu. Funkcija aplikacije se lahko spremeni."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Želite to aplikacijo posodobiti iz vira <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ta aplikacija običajno prejema posodobitve iz vira <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v tabličnem računalniku. Funkcija aplikacije se lahko spremeni.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Želite to aplikacijo posodobiti iz vira <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ta aplikacija običajno prejema posodobitve iz vira <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v televizorju. Funkcija aplikacije se lahko spremeni.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Želite to aplikacijo posodobiti iz vira <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ta aplikacija običajno prejema posodobitve iz vira <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v telefonu. Funkcija aplikacije se lahko spremeni.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija ni nameščena."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Namestitev paketa je bila blokirana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija ni bila nameščena, ker je paket v navzkrižju z obstoječim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index b73832e..ba16e06 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacioni u instalua."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Dëshiron ta instalosh këtë aplikacion?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Dëshiron ta përditësosh këtë aplikacion?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Të përditësohet ky aplikacion nga <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKy aplikacion zakonisht merr përditësime nga <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Duke përditësuar nga një burim tjetër, mund të marrësh përditësime të ardhshme nga çdo burim në telefonin tënd. Funksionaliteti i aplikacionit mund të ndryshojë."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Aplikacioni nuk u instalua."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalimi paketës u bllokua."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacioni nuk u instalua pasi paketa është në konflikt me një paketë ekzistuese."</string>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index 474e3ee..9e17716 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Апликација је инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Желите да инсталирате ову апликацију?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Желите да ажурирате ову апликацију?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Желите да ажурирате ову апликацију из извора <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nОва апликација се обично ажурира из извора <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на телефону. Функције апликације могу да се промене."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Ажурирајте ову апликацију код: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ова апликација обично добија ажурирања од: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на таблету. Функције апликације ће се можда променити.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Ажурирајте ову апликацију код: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ова апликација обично добија ажурирања од: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на ТВ-у. Функције апликације ће се можда променити.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Ажурирајте ову апликацију код: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Ова апликација обично добија ажурирања од: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на телефону. Функције апликације ће се можда променити.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Апликација није инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирање пакета је блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација није инсталирана јер је пакет неусаглашен са постојећим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index 3fa54e8..524b2c7 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Appen har installerats."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vill du installera den här appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vill du uppdatera den här appen?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vill du uppdatera den här appen från <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAppen tar vanligtvis emot uppdateringar från <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Genom att uppdatera från en annan källa kan du komma att ta emot framtida uppdateringar från olika källor på telefonen. Appfunktioner kan förändras."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Appen har inte installerats."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketet har blockerats för installation."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen har inte installerats på grund av en konflikt mellan detta paket och ett befintligt paket."</string>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index 59d927e..f51a881 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Imesakinisha programu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ungependa kusakinisha programu hii?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ungependa kusasisha programu hii?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Ungependa kusasisha programu hii kutoka kwenye <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nProgramu hii kwa kawaida hupokea masasisho kutoka <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kwa kusasisha kutoka chanzo tofauti, huenda ukapokea masasisho ya siku zijazo kutoka chanzo chochote kwenye simu yako. Utendaji wa programu unaweza kubadilika."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Imeshindwa kusakinisha programu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Kifurushi kimezuiwa kisisakinishwe."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Programu haikusakinishwa kwa sababu kifurushi kinakinzana na kifurushi kingine kilichopo."</string>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index 52cc628..2a4929c 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ஆப்ஸ் நிறுவப்பட்டது."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"இந்த ஆப்ஸை நிறுவ வேண்டுமா?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> இலிருந்து இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?\n\nபொதுவாக இந்த ஆப்ஸ்<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> இலிருந்து புதுப்பிப்புகளைப் பெறும். வேறொன்றின் மூலம் புதுப்பித்தால் எதிர்காலத்தில் மொபைலில் வேறு இடத்திலிருந்து புதுப்பிப்புகளை நீங்கள் பெறக்கூடும். ஆப்ஸ் செயல்பாடுகள் மாறுபடக்கூடும்."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ஆப்ஸ் நிறுவப்படவில்லை."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"இந்தத் தொகுப்பு நிறுவப்படுவதிலிருந்து தடுக்கப்பட்டது."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"இந்தத் தொகுப்பு ஏற்கனவே உள்ள தொகுப்புடன் முரண்படுவதால் ஆப்ஸ் நிறுவப்படவில்லை."</string>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 6f2a0d6..1013e3d 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"యాప్ ఇన్స్టాల్ చేయబడింది."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"మీరు ఈ యాప్ను ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"మీరు ఈ యాప్ను అప్డేట్ చేయాలనుకుంటున్నారా?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ద్వారా ఈ యాప్ను అప్డేట్ చేయాలా?\n\nఈ యాప్ సాధారణంగా <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> నుండి అప్డేట్లను అందుకుంటుంది. వేరే సోర్స్ ద్వారా అప్డేట్ చేయడం వల్ల, భవిష్యత్తులో మీ ఫోన్లోని ఏ సోర్స్ ద్వారా అయినా అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>ఈ యాప్ను <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> నుండి అప్డేట్ చేయాలా?</p><p>ఈ యాప్ సాధారణంగా <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> నుండి అప్డేట్లను స్వీకరిస్తుంది. విభిన్నమైన సోర్స్ నుండి అప్డేట్ చేయడం ద్వారా, మీరు టాబ్లెట్లోని ఏదైనా సోర్స్ నుండి భవిష్యత్తు అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>ఈ యాప్ను <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> నుండి అప్డేట్ చేయాలా?</p><p>ఈ యాప్ సాధారణంగా <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> నుండి అప్డేట్లను స్వీకరిస్తుంది. విభిన్నమైన సోర్స్ నుండి అప్డేట్ చేయడం ద్వారా, మీరు TVలోని ఏదైనా సోర్స్ నుండి భవిష్యత్తు అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>ఈ యాప్ను <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> నుండి అప్డేట్ చేయాలా?</p><p>ఈ యాప్ సాధారణంగా <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b> నుండి అప్డేట్లను స్వీకరిస్తుంది. విభిన్న సోర్స్ నుండి అప్డేట్ చేయడం ద్వారా, మీరు ఫోన్లోని ఏదైనా సోర్స్ నుండి భవిష్యత్తు అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ప్యాకేజీ ఇన్స్టాల్ కాకుండా బ్లాక్ చేయబడింది."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ప్యాకేజీ, అలాగే ఇప్పటికే ఉన్న ప్యాకేజీ మధ్య వైరుధ్యం ఉన్నందున యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index 8a01bb4..1206794 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ติดตั้งแอปแล้ว"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"คุณต้องการติดตั้งแอปนี้ไหม"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"คุณต้องการอัปเดตแอปนี้ไหม"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"อัปเดตแอปนี้จาก <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ไหม\n\nโดยปกติแล้ว แอปนี้จะได้รับการอัปเดตจาก <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> การอัปเดตจากแหล่งที่มาอื่นอาจทำให้โทรศัพท์ของคุณได้รับการอัปเดตจากแหล่งที่มาใดก็ได้ในอนาคต ฟังก์ชันการทำงานของแอปอาจมีการเปลี่ยนแปลง"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ไม่ได้ติดตั้งแอป"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"มีการบล็อกแพ็กเกจไม่ให้ติดตั้ง"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ไม่ได้ติดตั้งแอปเพราะแพ็กเกจขัดแย้งกับแพ็กเกจที่มีอยู่"</string>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 37dbed9..ad8e900 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Na-install na ang app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Gusto mo bang i-install ang app na ito?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Gusto mo bang i-update ang app na ito?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"I-update itong app na mula sa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKaraniwang nakakatanggap ang app na ito ng mga update mula sa <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Sa pag-update mula sa ibang pinagmulan, puwede kang makatanggap ng mga update mula sa anumang pinagmulan sa iyong telepono sa hinaharap. Posibleng magbago ang functionality ng app."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Hindi na-install ang app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Na-block ang pag-install sa package."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Hindi na-install ang app dahil nagkakaproblema ang package sa isang dati nang package."</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 8c384c1..259b92a 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Uygulama yüklendi."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu uygulamayı yüklemek istiyor musunuz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu uygulamayı güncellemek istiyor musunuz?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu uygulama <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> kaynağından güncellensin mi?\n\nBu uygulama genellikle <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> kaynağından güncelleme alır. Farklı bir kaynaktan güncellerseniz ileride telefonunuzda herhangi bir kaynaktan güncelleme alabilirsiniz. Uygulama işlevselliği değişebilir."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Uygulama yüklenmedi."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin yüklemesi engellendi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Paket, mevcut bir paketle çakıştığından uygulama yüklenemedi."</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index f4b594e..e9d1925 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Програму встановлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установити цей додаток?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Оновити цей додаток?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Оновити цей додаток через <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗазвичай цей додаток отримує оновлення в інший спосіб (<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>). Якщо встановити оновлення з іншого джерела, надалі на ваш телефон зможуть надходити оновлення з будь-яких джерел. Це може змінити функції додатка."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Програму не встановлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Встановлення пакета заблоковано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Додаток не встановлено, оскільки пакет конфліктує з наявним пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml
index fc4b26b..2bf3ba2f 100644
--- a/packages/PackageInstaller/res/values-ur/strings.xml
+++ b/packages/PackageInstaller/res/values-ur/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"ایپ انسٹال ہو گئی۔"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"کیا آپ یہ ایپ انسٹال کرنا چاہتے ہیں؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"کیا آپ یہ ایپ اپ ڈیٹ کرنا چاہتے ہیں؟"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"اس ایپ کو <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> سے اپ ڈیٹ کریں؟\n\n اس ایپ کو عام طور پر <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> سے اپ ڈیٹس موصول ہوتی ہیں۔ کسی مختلف ذریعے سے اپ ڈیٹ کر کے، آپ اپنے فون پر کسی بھی ذریعے سے مستقبل کی اپ ڈیٹس حاصل کر سکتے ہیں۔ ایپ کی فعالیت تبدیل ہو سکتی ہے۔"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"ایپ انسٹال نہیں ہوئی۔"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"پیکج کو انسٹال ہونے سے مسدود کر دیا گیا تھا۔"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ایپ انسٹال نہیں ہوئی کیونکہ پیکج ایک موجودہ پیکیج سے متصادم ہے۔"</string>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index f32ae7d..7597fb2 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"Ilova o‘rnatildi."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu ilovani oʻrnatmoqchimisiz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu ilova yangilansinmi?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu ilova <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> orqali yangilansinmi?\n\nBu ilova odatda <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> orqali yangilanishlar oladi. Boshqa manbadan yangilash orqali siz kelajakdagi yangilanishlarni telefoningizda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Bu ilovani bundan yangilash: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Bu ilova odatda yangilanishlarni bundan oladi: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Boshqa manbadan yangilash orqali kelgusi yangilanishlarni planshetda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Bu ilovani bundan yangilash: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Bu ilova odatda yangilanishlarni bundan oladi: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Boshqa manbadan yangilash orqali kelgusi yangilanishlarni televizorda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Bu ilovani bundan yangilash: <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Bu ilova odatda yangilanishlarni bundan oladi: <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Boshqa manbadan yangilash orqali kelgusi yangilanishlarni telefonda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Ilova o‘rnatilmadi."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paket o‘rnatilishga qarshi bloklangan."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Paket mavjud paket bilan zid kelganligi uchun ilovani o‘rnatib bo‘lmadi."</string>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index 051bc54..9af4ac2 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Ứng dụng đã được cài đặt."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bạn có muốn cài đặt ứng dụng này không?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bạn có muốn cập nhật ứng dụng này không?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Cập nhật ứng dụng này của <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nỨng dụng này thường nhận thông tin cập nhật từ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Khi cập nhật từ một nguồn khác, trong tương lai, bạn có thể nhận thông tin cập nhật từ nguồn bất kỳ trên điện thoại của bạn. Chức năng ứng dụng có thể thay đổi."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Ứng dụng chưa được cài đặt."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Đã chặn cài đặt gói."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Chưa cài đặt được ứng dụng do gói xung đột với một gói hiện có."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index c33c7ca..eb6d0f2 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"已安装应用。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安装此应用吗?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此应用吗?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要通过<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>更新此应用吗?\n\n此应用通常通过<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>接收更新。如果通过其他来源更新,手机未来可能会收到任何来源的更新。应用功能可能会变化。"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>要通过<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>更新此应用?</p><p>此应用通常从<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>接收更新。如果通过其他来源更新,平板电脑未来可能会收到任何来源的更新。应用功能可能会改变。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>要通过<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>更新此应用?</p><p>此应用通常从<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>接收更新。如果通过其他来源更新,电视未来可能会收到任何来源的更新。应用功能可能会改变。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>要通过<b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>更新此应用?</p><p>此应用通常从<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>接收更新。如果通过其他来源更新,手机未来可能会收到任何来源的更新。应用功能可能会改变。</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"未安装应用。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系统已禁止安装该软件包。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"应用未安装:软件包与现有软件包存在冲突。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 0bfbd6e..184aa53 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝此應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此應用程式嗎?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要從「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新此應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新此應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,平板電腦未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,TV 裝置未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"套件已遭封鎖,無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"套件與現有的套件發生衝突,無法安裝應用程式。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index 4f0f669..0d9e266 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -26,11 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝這個應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新這個應用程式嗎?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
- <skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
- <skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新這個應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新這個應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,平板電腦未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,TV 裝置未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」<b></b>更新這個應用程式嗎?</p><p>這個應用程式一般是接收「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」<b></b>的更新。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會變動。</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系統已封鎖這個套件,因此無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"應用程式套件與現有套件衝突,因此未能完成安裝。"</string>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index bcc4b71..f714b38 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -26,11 +26,12 @@
<string name="install_done" msgid="5987363587661783896">"Uhlelo lokusebenza olufakiwe."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingabe ufuna ukufaka le app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingabe ufuna ukubuyekeza le app?"</string>
- <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7994800761970572198) -->
<skip />
- <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <!-- no translation found for install_confirm_question_update_owner_reminder (2435174886412089791) -->
<skip />
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Buyekeza le app kusuka ku-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNgokuvamile le app ithola izibuyekezo kusuka ku-<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ngokubuyekeza kusuka kumthombo ohlukile, ungase uthole izibuyekezo zesikhathi esizayo kusuka kunoma yimuphi umthombo efonini yakho. Okwenziwa yi-app kungase kushintshe."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (7155138616126795839) -->
+ <skip />
<string name="install_failed" msgid="5777824004474125469">"Uhlelo lokusebenza alufakiwe."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Iphakheji livinjiwe kusukela ekufakweni."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Uhlelo lokusebenza alufakiwe njengoba ukuphakheja kushayisana nephakheji elikhona."</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 229b7a7..1231bb3 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -51,7 +51,6 @@
public class InstallStart extends Activity {
private static final String TAG = InstallStart.class.getSimpleName();
- private static final String DOWNLOADS_AUTHORITY = "downloads";
private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = 1;
private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = 2;
@@ -103,6 +102,8 @@
boolean isDocumentsManager = checkPermission(Manifest.permission.MANAGE_DOCUMENTS,
-1, callingUid) == PackageManager.PERMISSION_GRANTED;
+ boolean isSystemDownloadsProvider = PackageUtil.getSystemDownloadsProviderInfo(
+ mPackageManager, callingUid) != null;
boolean isTrustedSource = false;
if (sourceInfo != null && sourceInfo.isPrivilegedApp()) {
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false) || (
@@ -111,7 +112,7 @@
== PackageManager.PERMISSION_GRANTED);
}
- if (!isTrustedSource && !isSystemDownloadsProvider(callingUid) && !isDocumentsManager
+ if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager
&& originatingUid != Process.INVALID_UID) {
final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
if (targetSdkVersion < 0) {
@@ -241,17 +242,6 @@
return null;
}
- private boolean isSystemDownloadsProvider(int uid) {
- final ProviderInfo downloadProviderPackage = getPackageManager().resolveContentProvider(
- DOWNLOADS_AUTHORITY, 0);
- if (downloadProviderPackage == null) {
- // There seems to be no currently enabled downloads provider on the system.
- return false;
- }
- final ApplicationInfo appInfo = downloadProviderPackage.applicationInfo;
- return ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
- && uid == appInfo.uid);
- }
@NonNull
private boolean canPackageQuery(int callingUid, Uri packageUri) {
@@ -266,7 +256,7 @@
if (callingPackages == null) {
return false;
}
- for (String callingPackage: callingPackages) {
+ for (String callingPackage : callingPackages) {
try {
if (mPackageManager.canPackageQuery(callingPackage, targetPackage)) {
return true;
@@ -346,7 +336,6 @@
* Create a new dialog.
*
* @param id The id of the dialog (determines dialog type)
- *
* @return The dialog
*/
private DialogFragment createDialog(int id) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 411f1fa..bc7fa02 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -265,6 +265,15 @@
}
private String getPackageNameForUid(int sourceUid) {
+ // If the sourceUid belongs to the system downloads provider, we explicitly return the
+ // name of the Download Manager package. This is because its UID is shared with multiple
+ // packages, resulting in uncertainty about which package will end up first in the list
+ // of packages associated with this UID
+ ApplicationInfo systemDownloadProviderInfo = PackageUtil.getSystemDownloadsProviderInfo(
+ mPm, sourceUid);
+ if (systemDownloadProviderInfo != null) {
+ return systemDownloadProviderInfo.packageName;
+ }
String[] packagesForUid = mPm.getPackagesForUid(sourceUid);
if (packagesForUid == null) {
return null;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index ff0e5fb..c2d4f18 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -26,6 +26,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -48,7 +49,7 @@
* used in the package installer application.
*/
public class PackageUtil {
- private static final String LOG_TAG = PackageUtil.class.getSimpleName();
+ private static final String LOG_TAG = "PackageInstaller";
public static final String PREFIX="com.android.packageinstaller.";
public static final String INTENT_ATTR_INSTALL_STATUS = PREFIX+"installStatus";
@@ -56,6 +57,7 @@
public static final String INTENT_ATTR_PERMISSIONS_LIST=PREFIX+"PermissionsList";
//intent attribute strings related to uninstall
public static final String INTENT_ATTR_PACKAGE_NAME=PREFIX+"PackageName";
+ private static final String DOWNLOADS_AUTHORITY = "downloads";
/**
* Utility method to get package information for a given {@link File}
@@ -245,4 +247,26 @@
getActivity().finish();
}
}
+
+ /**
+ * Determines if the UID belongs to the system downloads provider and returns the
+ * {@link ApplicationInfo} of the provider
+ *
+ * @param uid UID of the caller
+ * @return {@link ApplicationInfo} of the provider if a downloads provider exists,
+ * it is a system app, and its UID matches with the passed UID, null otherwise.
+ */
+ public static ApplicationInfo getSystemDownloadsProviderInfo(PackageManager pm, int uid) {
+ final ProviderInfo providerInfo = pm.resolveContentProvider(
+ DOWNLOADS_AUTHORITY, 0);
+ if (providerInfo == null) {
+ // There seems to be no currently enabled downloads provider on the system.
+ return null;
+ }
+ ApplicationInfo appInfo = providerInfo.applicationInfo;
+ if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 && uid == appInfo.uid) {
+ return appInfo;
+ }
+ return null;
+ }
}
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 844e9c9..4dcad10 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -23,12 +23,14 @@
<style name="Theme.SelectPrinterActivity"
parent="android:style/Theme.DeviceDefault.Light">
<item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+ <item name="android:windowLightStatusBar">true</item>
</style>
<style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowLightStatusBar">true</item>
</style>
</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
index 22a6f59..102fdc8 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"విస్మరించు"</string>
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"విస్మరించండి"</string>
</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml b/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml
index db11a76..dc3af28 100644
--- a/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml
+++ b/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Толығырақ"</string>
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Толық ақпарат"</string>
</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml
index 8b211e7..567c4bc 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settings_label" msgid="5948970810295631236">"ସେଟିଂସ୍"</string>
+ <string name="settings_label" msgid="5948970810295631236">"ସେଟିଂସ"</string>
</resources>
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index fac63361..329d80e 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -15,8 +15,8 @@
*/
plugins {
- id(libs.plugins.android.library.get().pluginId)
- id(libs.plugins.kotlin.android.get().pluginId)
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
jacoco
}
@@ -69,7 +69,7 @@
implementation("com.airbnb.android:lottie-compose:5.2.0")
androidTestImplementation(project(":testutils"))
- androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing")
+ androidTestImplementation(libs.dexmaker.mockito)
}
tasks.register<JacocoReport>("coverageReport") {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
index 57bb838..81bbc24 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
@@ -18,7 +18,7 @@
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.AnimatedContentScope
+import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
@@ -78,14 +78,10 @@
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.Center,
route: String? = null,
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- { fadeIn(animationSpec = tween(700)) },
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- { fadeOut(animationSpec = tween(700)) },
- popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- enterTransition,
- popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition) = { fadeIn(animationSpec = tween(700)) },
+ exitTransition: (AnimatedScope.() -> ExitTransition) = { fadeOut(animationSpec = tween(700)) },
+ popEnterTransition: (AnimatedScope.() -> EnterTransition) = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition) = exitTransition,
builder: NavGraphBuilder.() -> Unit
) {
AnimatedNavHost(
@@ -123,14 +119,10 @@
graph: NavGraph,
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.Center,
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- { fadeIn(animationSpec = tween(700)) },
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- { fadeOut(animationSpec = tween(700)) },
- popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- enterTransition,
- popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition) = { fadeIn(animationSpec = tween(700)) },
+ exitTransition: (AnimatedScope.() -> ExitTransition) = { fadeOut(animationSpec = tween(700)) },
+ popEnterTransition: (AnimatedScope.() -> EnterTransition) = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition) = exitTransition,
) {
val lifecycleOwner = LocalLifecycleOwner.current
@@ -168,7 +160,7 @@
val backStackEntry = visibleEntries.lastOrNull()
if (backStackEntry != null) {
- val finalEnter: AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition = {
+ val finalEnter: AnimatedScope.() -> EnterTransition = {
val targetDestination = targetState.destination as AnimatedComposeNavigator.Destination
if (composeNavigator.isPop.value) {
@@ -182,7 +174,7 @@
}
}
- val finalExit: AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition = {
+ val finalExit: AnimatedScope.() -> ExitTransition = {
val initialDestination =
initialState.destination as AnimatedComposeNavigator.Destination
@@ -245,19 +237,16 @@
DialogHost(dialogNavigator)
}
-@ExperimentalAnimationApi
-internal val enterTransitions =
- mutableMapOf<String?,
- (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?>()
+@OptIn(ExperimentalAnimationApi::class)
+internal typealias AnimatedScope = AnimatedContentTransitionScope<NavBackStackEntry>
@ExperimentalAnimationApi
-internal val exitTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?>()
+internal val enterTransitions = mutableMapOf<String?, (AnimatedScope.() -> EnterTransition?)?>()
@ExperimentalAnimationApi
-internal val popEnterTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?>()
+internal val exitTransitions = mutableMapOf<String?, (AnimatedScope.() -> ExitTransition?)?>()
+@ExperimentalAnimationApi
+internal val popEnterTransitions = mutableMapOf<String?, (AnimatedScope.() -> EnterTransition?)?>()
@ExperimentalAnimationApi
-internal val popExitTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?>()
+internal val popExitTransitions = mutableMapOf<String?, (AnimatedScope.() -> ExitTransition?)?>()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
index 9e58603..bf92f5d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
@@ -16,7 +16,6 @@
package com.android.settingslib.spa.framework.compose
-import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
@@ -25,9 +24,7 @@
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink
-import androidx.navigation.NavGraph
import androidx.navigation.NavGraphBuilder
-import androidx.navigation.compose.navigation
import androidx.navigation.get
/**
@@ -47,14 +44,10 @@
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = null,
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = null,
- popEnterTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?
- )? = enterTransition,
- popExitTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?
- )? = exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition?)? = null,
+ exitTransition: (AnimatedScope.() -> ExitTransition?)? = null,
+ popEnterTransition: (AnimatedScope.() -> EnterTransition?)? = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition?)? = exitTransition,
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit
) {
addDestination(
@@ -76,43 +69,3 @@
}
)
}
-
-/**
- * Construct a nested [NavGraph]
- *
- * @param startDestination the starting destination's route for this NavGraph
- * @param route the destination's unique route
- * @param arguments list of arguments to associate with destination
- * @param deepLinks list of deep links to associate with the destinations
- * @param enterTransition callback to define enter transitions for destination in this NavGraph
- * @param exitTransition callback to define exit transitions for destination in this NavGraph
- * @param popEnterTransition callback to define pop enter transitions for destination in this
- * NavGraph
- * @param popExitTransition callback to define pop exit transitions for destination in this NavGraph
- * @param builder the builder used to construct the graph
- *
- * @return the newly constructed nested NavGraph
- */
-@ExperimentalAnimationApi
-public fun NavGraphBuilder.navigation(
- startDestination: String,
- route: String,
- arguments: List<NamedNavArgument> = emptyList(),
- deepLinks: List<NavDeepLink> = emptyList(),
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = null,
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = null,
- popEnterTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?
- )? = enterTransition,
- popExitTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?
- )? = exitTransition,
- builder: NavGraphBuilder.() -> Unit
-) {
- navigation(startDestination, route, arguments, deepLinks, builder).apply {
- enterTransition?.let { enterTransitions[route] = enterTransition }
- exitTransition?.let { exitTransitions[route] = exitTransition }
- popEnterTransition?.let { popEnterTransitions[route] = popEnterTransition }
- popExitTransition?.let { popExitTransitions[route] = popExitTransition }
- }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index 79635a0..aa148b0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -20,20 +20,12 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
-import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.TabRow
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalConfiguration
import com.android.settingslib.spa.framework.theme.SettingsDimension
import kotlin.math.absoluteValue
import kotlinx.coroutines.launch
@@ -49,7 +41,7 @@
Column {
val coroutineScope = rememberCoroutineScope()
- val pagerState = rememberPageStateFixed()
+ val pagerState = rememberPagerState { titles.size }
TabRow(
selectedTabIndex = pagerState.currentPage,
@@ -72,46 +64,8 @@
}
}
- HorizontalPager(pageCount = titles.size, state = pagerState) { page ->
+ HorizontalPager(state = pagerState) { page ->
content(page)
}
}
}
-
-/**
- * Gets the state of [PagerState].
- *
- * This is a work around.
- *
- * TODO: Remove this and replace with rememberPageState() after the Compose Foundation 1.5.0-alpha04
- * updated in the platform.
- */
-@Composable
-@OptIn(ExperimentalFoundationApi::class)
-private fun rememberPageStateFixed(): PagerState {
- var currentPage by rememberSaveable { mutableStateOf(0) }
- var targetPage by rememberSaveable { mutableStateOf(-1) }
- val pagerState = rememberPagerState()
- val configuration = LocalConfiguration.current
- var lastScreenWidthDp by rememberSaveable { mutableStateOf(-1) }
- val screenWidthDp = configuration.screenWidthDp
- LaunchedEffect(screenWidthDp) {
- // Reset pager state to fix an issue after configuration change.
- // When we declare android:configChanges in the manifest, the pager state is in a weird
- // state after configuration change.
- targetPage = currentPage
- lastScreenWidthDp = screenWidthDp
- }
- LaunchedEffect(targetPage) {
- if (targetPage != -1) {
- pagerState.scrollToPage(targetPage)
- targetPage = -1
- }
- }
- SideEffect {
- if (lastScreenWidthDp == screenWidthDp) {
- currentPage = pagerState.currentPage
- }
- }
- return pagerState
-}
diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp
index b4c67cc..f9e64ae 100644
--- a/packages/SettingsLib/Spa/tests/Android.bp
+++ b/packages/SettingsLib/Spa/tests/Android.bp
@@ -31,7 +31,6 @@
"SpaLib",
"SpaLibTestUtils",
"androidx.compose.runtime_runtime",
- "androidx.lifecycle_lifecycle-runtime-testing",
"androidx.test.ext.junit",
"androidx.test.runner",
"mockito-target-minus-junit4",
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index 2c1e1c2..e4d56cc 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -29,6 +29,7 @@
"androidx.compose.runtime_runtime",
"androidx.compose.ui_ui-test-junit4",
"androidx.compose.ui_ui-test-manifest",
+ "androidx.lifecycle_lifecycle-runtime-testing",
"mockito",
"truth-prebuilt",
],
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle.kts b/packages/SettingsLib/Spa/testutils/build.gradle.kts
index c3df9bc..f5a22c9 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle.kts
+++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts
@@ -15,8 +15,8 @@
*/
plugins {
- id(libs.plugins.android.library.get().pluginId)
- id(libs.plugins.kotlin.android.get().pluginId)
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
}
val jetpackComposeVersion: String? by extra
@@ -26,7 +26,7 @@
sourceSets {
sourceSets.getByName("main") {
- java.setSrcDirs(listOf("src"))
+ kotlin.setSrcDirs(listOf("src"))
manifest.srcFile("AndroidManifest.xml")
}
}
@@ -40,7 +40,8 @@
api("androidx.arch.core:core-testing:2.2.0-alpha01")
api("androidx.compose.ui:ui-test-junit4:$jetpackComposeVersion")
+ api("androidx.lifecycle:lifecycle-runtime-testing")
api(libs.truth)
- api(libs.dexmaker.mockito)
+ api("org.mockito:mockito-core:2.21.0")
debugApi("androidx.compose.ui:ui-test-manifest:$jetpackComposeVersion")
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 030b70a7..07e4235 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -42,7 +42,6 @@
showInstantApps: Boolean = false,
noMoreOptions: Boolean = false,
matchAnyUserForAdmin: Boolean = false,
- primaryUserOnly: Boolean = false,
noItemMessage: String? = null,
moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
header: @Composable () -> Unit = {},
@@ -60,7 +59,7 @@
}
},
) { bottomPadding, searchQuery ->
- UserProfilePager(primaryUserOnly) { userGroup ->
+ UserProfilePager { userGroup ->
val appListInput = AppListInput(
config = AppListConfig(
userIds = userGroup.userInfos.map { it.id },
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
index b5a4929..6a76c93 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/UserProfilePager.kt
@@ -38,14 +38,9 @@
)
@Composable
-fun UserProfilePager(
- primaryUserOnly: Boolean = false,
- content: @Composable (userGroup: UserGroup) -> Unit,
-) {
+fun UserProfilePager(content: @Composable (userGroup: UserGroup) -> Unit) {
val context = LocalContext.current
- val userGroups = remember {
- context.userManager.getUserGroups(primaryUserOnly)
- }
+ val userGroups = remember { context.userManager.getUserGroups() }
val titles = remember {
val enterpriseRepository = EnterpriseRepository(context)
userGroups.map { userGroup ->
@@ -60,10 +55,9 @@
}
}
-private fun UserManager.getUserGroups(primaryUserOnly: Boolean): List<UserGroup> {
+private fun UserManager.getUserGroups(): List<UserGroup> {
val userGroupList = mutableListOf<UserGroup>()
val profileToShowInSettingsList = getProfiles(UserHandle.myUserId())
- .filter { userInfo -> !primaryUserOnly || userInfo.isPrimary }
.map { userInfo -> userInfo to getUserProperties(userInfo.userHandle).showInSettings }
profileToShowInSettingsList.filter { it.second == UserProperties.SHOW_IN_SETTINGS_WITH_PARENT }
diff --git a/packages/SettingsLib/res/drawable/dialog_btn_filled.xml b/packages/SettingsLib/res/drawable/dialog_btn_filled.xml
index 14cb1de9..0614f9d 100644
--- a/packages/SettingsLib/res/drawable/dialog_btn_filled.xml
+++ b/packages/SettingsLib/res/drawable/dialog_btn_filled.xml
@@ -22,12 +22,12 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/button_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/button_corner_radius"/>
<solid android:color="?androidprv:attr/colorAccentPrimary"/>
<padding android:left="@dimen/dialog_button_horizontal_padding"
android:top="@dimen/dialog_button_vertical_padding"
diff --git a/packages/SettingsLib/res/drawable/dialog_btn_outline.xml b/packages/SettingsLib/res/drawable/dialog_btn_outline.xml
index 1e77759..a920b50 100644
--- a/packages/SettingsLib/res/drawable/dialog_btn_outline.xml
+++ b/packages/SettingsLib/res/drawable/dialog_btn_outline.xml
@@ -22,16 +22,15 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/button_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
- <corners android:radius="?android:attr/buttonCornerRadius"/>
+ <corners android:radius="@dimen/button_corner_radius"/>
<solid android:color="@android:color/transparent"/>
<stroke android:color="?androidprv:attr/colorAccentPrimaryVariant"
- android:width="1dp"
- />
+ android:width="1dp"/>
<padding android:left="@dimen/dialog_button_horizontal_padding"
android:top="@dimen/dialog_button_vertical_padding"
android:right="@dimen/dialog_button_horizontal_padding"
diff --git a/packages/SettingsLib/res/layout/dialog_with_icon.xml b/packages/SettingsLib/res/layout/dialog_with_icon.xml
index 55d12eb..2f30508 100644
--- a/packages/SettingsLib/res/layout/dialog_with_icon.xml
+++ b/packages/SettingsLib/res/layout/dialog_with_icon.xml
@@ -63,7 +63,6 @@
android:id="@+id/button_cancel"
style="@style/DialogButtonNegative"
android:layout_width="wrap_content"
- android:buttonCornerRadius="28dp"
android:layout_height="wrap_content"
android:visibility="gone"/>
@@ -78,7 +77,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DialogButtonNegative"
- android:buttonCornerRadius="40dp"
android:visibility="gone"/>
<Space
@@ -92,8 +90,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DialogButtonPositive"
- android:visibility="gone"
- />
+ android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 556768f..a005693 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-oudio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD oudio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Gehoortoestelle"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-oudio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Gekoppel aan gehoortoestelle"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Gekoppel aan LE-oudio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Gekoppel aan media-oudio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Gekoppel aan foonoudio"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruik vir foonoudio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruik vir lêeroordrag"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruik vir invoer"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Gebruik vir gehoortoestelle"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gebruik vir LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Bind saam"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BIND SAAM"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skermlaag wys huidige raakdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Wys tikke"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Wys visuele terugvoer vir tikke"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Wys sleuteldrukke"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Wys visuele terugvoer vir fisieke sleuteldrukke"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Wys oppervlakopdaterings"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flits totale vensteroppervlakke wanneer dit opdateer"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Wys aansigopdaterings"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index cb6ca3d..28ca2bb 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"የሲም መዳረሻ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"ኤችዲ ኦዲዮ፦ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"ኤችዲ ኦዲዮ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"መስሚያ አጋዥ መሣሪያዎች"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ኦዲዮ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ከመስሚያ አጋዥ መሣሪያዎች ጋር ተገናኝቷል"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ከLE ኦዲዮ ጋር ተገናኝቷል"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ወደ ማህደረ መረጃ አውዲዮ ተያይዟል"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ወደ ስልክ አውዲዮ ተያይዟል"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ለስልክ ድምፅ ተጠቀም"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ለፋይል ዝውውር ተጠቀም"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ለውፅአት ተጠቀም"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ለመስሚያ አጋዥ መሣሪያዎች ይጠቀሙ"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"ለLE_AUDIO ይጠቀሙ"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"አጣምር"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"አጣምር"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"የማያ ተደራቢ የአሁኑን የCPU አጠቃቀም እያሳየ ነው።"</string>
<string name="show_touches" msgid="8437666942161289025">"ነካ ማድረጎችን አሳይ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ለነካ ማድረጎች ምስላዊ ግብረመልስን አሳይ"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"የቁልፍ ጭነቶችን አሳይ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ለአካላዊ የቁልፍ ጭነቶች የሚታይ ግብረመልስን አሳይ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"የወለል ዝማኔዎችን አሳይ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"የመስኮት ወለሎች ሲዘምኑ መላ መስኮቱን አብለጭልጭ"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"የእይታ ዝማኔዎችን አሳይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 024f591..aff5c81 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"الوصول إلى شريحة SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"صوت عالي الدقة: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"صوت عالي الدقة"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"سماعات الأذن الطبية"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"تم توصيل سماعات الأذن الطبية"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"متصل بـ LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"متصل بالإعدادات الصوتية للوسائط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"متصل بالإعدادات الصوتية للهاتف"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"الاستخدام لإعدادات الهاتف الصوتية"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"استخدامه لنقل الملفات"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"استخدام للإدخال"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"استخدام سماعات الأذن الطبية"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"الاستخدام لـ LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"إقران"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"إقران"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"عرض بيانات اللمس الحالية فوق المحتوى على الشاشة"</string>
<string name="show_touches" msgid="8437666942161289025">"عرض النقرات"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"عرض التعليقات المرئية للنقرات"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"عرض الضغطات على المفاتيح"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"عرض الملاحظات المرئية للضغطات الفعلية على المفاتيح"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"عرض تحديثات السطح"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"وميض أسطح النوافذ بالكامل عندما يتم تحديثها"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"إظهار تحديثات العرض"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 40fffef..c1128ae 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ছিমৰ এক্সেছ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"এইচ্ছডি অডিঅ’"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"শ্ৰৱণ যন্ত্ৰ"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE অডিঅ’"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"শ্ৰৱণ যন্ত্ৰৰ সৈতে সংযোগ কৰা হৈছে"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিঅ’ৰ সৈতে সংযোগ কৰক"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ফ\'ন অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ফাইল স্থানান্তৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ইনপুটৰ বাবে ব্যৱহাৰ কৰক"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"শ্ৰৱণ যন্ত্ৰৰ বাবে ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIOৰ বাবে ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"পেয়াৰ কৰক"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"পেয়াৰ কৰক"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"চলিত স্পৰ্শ-বিষয়ক তথ্যসহ স্ক্ৰীন অভাৰলে’"</string>
<string name="show_touches" msgid="8437666942161289025">"টেপসমূহ দেখুৱাওক"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"কী টিপা দেখুৱাওক"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ভৌতিক কী টিপাৰ ভিজুৱেল প্ৰতিক্ৰিয়া দেখুৱাওক"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"পৃষ্ঠভাগৰ আপডে’ট দেখুৱাওক"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"আপডে’ট হওতে গোটেই ৱিণ্ড পৃষ্ঠসমূহ ফ্লাশ্ব কৰক"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"ভিউৰ আপডে’ট দেখুৱাওক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 80cdf60..57b4694 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-karta giriş"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Eşitmə aparatları"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Eşitmə aparatlarına qoşuldu"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audiosuna qoşulub"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Media audioya birləşdirilib"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon audiosuna qoşulu"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Telefon audiosu istifadə edin"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Fayl transferi üçün istifadə edin"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Daxiletmə üçün istifadə edin"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Eşitmə aparatları üçün istifadə edin"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO üçün istifadə edin"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Qoşulsun"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"QOŞULSUN"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Toxunuş və jest datası göstərilsin"</string>
<string name="show_touches" msgid="8437666942161289025">"Vizual reaksiya"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Toxunuşa vizual reaksiya verilsin"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Düyməyə basma göstərilsin"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Fiziki düymə basılmaları üçün vizual rəy göstərin"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Səth yenilənməsi göstərilsin"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Pəncərə səthi təzələnəndə işıqlansın"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Baxış yenilənməsi göstərilsin"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index cb226b7..e9e0e90 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM kartici"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Slušni aparati"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Povezano sa slušnim aparatima"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa zvukom telefona"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Korišćenje za audio telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Korišćenje za prenos datoteka"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Koristi za ulaz"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Koristi za slušne aparate"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Koristite za LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Preklopni element sa trenutnim podacima o dodiru"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikazuj dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikazuje vizuelne povratne informacije za dodire"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Prikazuj pritiske tastera"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Prikazuje povratne informacije za pritiske tastera"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Osvetljava sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index dc32113..0f6112c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Доступ да SIM-карты"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Аўдыя ў HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Аўдыя ў HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слыхавыя апараты"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Слыхавыя апараты падключаны"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Падключана да LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Падключана да аўдыё медыа"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Падключана да аўдыё тэлефона"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Выкарыстоўваць для аўдыё тэлефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Выкарыстоўваць для перадачы файлаў"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Выкарыстоўваць для ўводу"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Выкарыстоўваць для слыхавых апаратаў"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Выкарыстоўваць для LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Спалучыць"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"СПАЛУЧЫЦЬ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Паказваць на экране націсканні і жэсты"</string>
<string name="show_touches" msgid="8437666942161289025">"Паказваць дакрананні"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Паказваць візуалізацыю дакрананняў"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Паказваць націсканні"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Паказваць візуальны водгук пры націсканні клавіш"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Абнаўленне паверхні"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Падсвяціць паверхню акна пры абнаўленні"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Паказаць абнаўленні"</string>
@@ -552,12 +547,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Гэты тэлефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Гэты планшэт"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не ўдаецца прайграць на гэтай прыладзе"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для пераключэння перайдзіце на іншую версію ўліковага запісу"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 2928dd9..abd90d0 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Достъп до SIM картата"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Висококачествено аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Висококачествено аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слухови апарати"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Установена е връзка със слухов апарат"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Свързано с LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Установена е връзка с медийно аудио"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Връзка със звука на телефона"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Използване на телефон за аудио"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Използване на за пренос на файлове"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Да се използва за въвеждане"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Използване за слухови апарати"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Използване за LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Сдвояване"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"СДВОЯВАНЕ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Насл. на екран показва текущи данни при докосване"</string>
<string name="show_touches" msgid="8437666942161289025">"Показване на докосванията"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Показване на визуална обр. връзка за докосванията"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Видими натиск. на клавиши"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Визуална обратна връзка при натискане на клавиши"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Актуализации на повърхн."</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Примигв. на целите повърхности на прозорците при актуализирането им"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Актуализации на изгледите"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index d8c991fe..b037b13 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"সিম অ্যাক্সেস"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD অডিও: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD অডিও"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"হিয়ারিং এড"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE অডিও"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"হিয়ারিং এডের সাথে কানেক্ট করা হয়েছে"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিও কানেক্ট করা হয়েছে"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিওতে কানেক্ট রয়েছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফোন অডিওতে কানেক্ট"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ইনপুটের জন্য ব্যবহার করুন"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"হিয়ারিং এডের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO-এর জন্য ব্যবহার করুন"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"যুক্ত করুন"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"যুক্ত করুন"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"স্ক্রিন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string>
<string name="show_touches" msgid="8437666942161289025">"আলতো চাপ দেখান"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"আলতো চাপ দিলে ভিজ্যুয়াল প্রতিক্রিয়া দেখান"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"প্রেস করা কী দেখুন"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"প্রেস করা ফিজিকাল কীয়ের জন্য ভিস্যুয়াল মতামত দেখুন"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"সারফেস আপডেটগুলি দেখান"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"সম্পূর্ণ উইন্ডোর সারফেস আপডেট হয়ে গেলে সেটিকে ফ্ল্যাশ করুন"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"ভিউয়ের আপডেট দেখুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ad973fb..1a37a3f 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM-u"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Slušni aparati"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Povezano je sa slušnim aparatima"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s LE zvukom"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano na zvuk telefona"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Koristi za zvuk telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Koristi za prijenos fajlova"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Koristi kao ulaz"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Korištenje za slušne aparate"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Koristi za: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Preklapanje ekrana s trenutnim podacima o dodiru"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikaz vizuelnih povratnih informacija za dodire"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Prikaži pritiskanja tipki"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Prikaži vizuelne povr. inform. za pritiske tipki"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja za površinu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Osvjetljava sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index a1e7933..233b3e1 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accés a la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Àudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Àudio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audiòfons"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"S\'ha connectat als audiòfons"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connectat a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connectat a l\'àudio del mitjà"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connectat a àudio del telèfon"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilitza-ho per a l\'àudio del telèfon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilitza per a la transferència de fitxers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilitza per a entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Utilitza per als audiòfons"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utilitza per a LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincula"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"VINCULA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposa les dades dels tocs a la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostra els tocs"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra la ubicació visual dels tocs"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostra les tecles premudes"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostra avisos visuals en prémer tecles físiques"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Canvis de superfície"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Il·lumina superfícies de finestres en actualitzar-se"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Actualitzacions de visualitzacions"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 11fb32d9..41d3d52 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Přístup k SIM kartě"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Naslouchátka"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Připojeno k naslouchátkům"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Připojeno k LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Připojeno ke zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Připojeno k náhlavní soupravě"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Umožňuje připojení náhlavní soupravy"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Použít pro přenos souborů"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Použít pro vstup"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Použít pro naslouchátka"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Používat pro LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Spárovat"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SPÁROVAT"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Překryvná vrstva zobrazuje aktuální data o dotycích"</string>
<string name="show_touches" msgid="8437666942161289025">"Zobrazovat klepnutí"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Zobrazovat vizuální zpětnou vazbu pro klepnutí"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Zobrazit stisknutí klávesy"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Zobrazit vizuální odezvu při stisknutí fyzické klávesy"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Zobrazit obnovení obsahu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Rozbliká obsah okna při aktualizaci"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ukazovat aktualizace zobrazení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 11e92de..30022d3 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Adgang til SIM-kort"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Høreapparater"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-lyd"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Forbundet til høreapparater"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Forbundet med LE-lyd"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Forbundet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Forbundet til telefonlyd"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Brug til telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Brug til filoverførsel"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Brug til input"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Brug til høreapparater"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Brug med LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Par"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ACCEPTÉR PARRING"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skærmoverlejringen viser de aktuelle berøringsdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Vis tryk"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vis visuel feedback ved tryk"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Vis tastetryk"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Vis visuel feedback ved fysiske tastetryk"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Vis overfladeopdateringer"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fremhæv hele vinduesoverflader, når de opdateres"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Se visningsopdateringer"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 3c9b177..e9d885a 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Zugriff auf SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-Audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hörgerät"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Mit Hörgerät verbunden"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Mit LE Audio verbunden"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbunden mit Medien-Audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbunden mit Telefon-Audio"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Für Telefon-Audio verwenden"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Für Dateiübertragung verwenden"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Für Eingabe verwenden"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Für Hörgerät verwenden"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Für LE_AUDIO verwenden"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppeln"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELN"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay mit aktuellen Daten zu Tippaktionen anzeigen"</string>
<string name="show_touches" msgid="8437666942161289025">"Fingertippen visualisieren"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Bei Fingertippen visuelles Feedback anzeigen"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Tastatureingaben anzeigen"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Visuelles Feedback für Tastatureingaben anzeigen"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Oberflächenaktualisierungen hervorheben"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Gesamte Fensteroberflächen blinken bei Aktualisierung"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Aktualisierungen von Ansichten hervorheben"</string>
@@ -552,12 +547,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Dieses Smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Dieses Tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock-Lautsprecher"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Wiedergabe auf diesem Gerät nicht möglich"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Zum Umstellen Kontoupgrade durchführen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d03581a..19413c1 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Πρόσβαση SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Ήχος HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Ήχος HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Βοηθήματα ακοής"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Σε σύνδεση με βοηθήματα ακοής"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Συνδέθηκε σε LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Συνδέθηκε σε ήχο πολυμέσων"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Συνδεδεμένο στον ήχο τηλεφώνου"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Χρήση για ήχο τηλεφώνου"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Χρήση για τη μεταφορά αρχείων"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Χρήση για είσοδο"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Χρήση για βοηθήματα ακοής"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Χρήση για LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Σύζευξη"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ΣΥΖΕΥΞΗ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Επικάλ.οθόνης για προβολή τρεχόντων δεδ/νων αφής"</string>
<string name="show_touches" msgid="8437666942161289025">"Εμφάνιση πατημάτων"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Εμφάνιση οπτικών σχολίων για πατήματα"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Εμφάν. πατημάτων πλήκτρων"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Εμφ. οπτικής ανάδρασης για πατήμ. φυσικών πλήκτρων"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Εμφάνιση ενημερώσεων επιφάνειας"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Προβολή Flash ολόκλ. των επιφ παραθ. όταν ενημερ."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Εμφάνιση ενημερ. προβολής"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 25d2dd2..58ea681 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Show key presses"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Show visual feedback for physical key presses"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 25d2dd2..58ea681 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Show key presses"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Show visual feedback for physical key presses"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 25d2dd2..58ea681 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Show key presses"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Show visual feedback for physical key presses"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index f4b4153..ae24ff0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso a SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audífonos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"audio de bajo consumo"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectado a audífonos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a audio de bajo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del dispositivo"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilizar para el audio del dispositivo"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilizar para la transferencia de archivos"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Usar para audífonos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincular"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Muestra los datos táctiles en la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar presiones"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Muestra la ubicación de las presiones en la pantalla"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Ver pulsaciones de teclas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Ver coment. visual para pulsac. de teclas físicas"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Ver actualiz. de superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Destello en superficie por actualización"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mostrar cambios de vista"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b6ed91e..df256e5 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso a tarjeta SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audífonos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectado a audífonos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio del medio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del teléfono"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilizar para audio del teléfono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Uso de la transferencia de archivos"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Usar con audífonos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar en LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Emparejar"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"EMPAREJAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superpone los datos de las pulsaciones en la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Muestra la ubicación de los toques en la pantalla"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Ver pulsación de teclas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Ver respuestas visuales al pulsar teclas físicas"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar cambios de superficies"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Hace parpadear todas las superficies de la ventana cuando se actualizan"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver actualizaciones de vista"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 023af0b..be847b3 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Juurdepääs SIM-ile"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-heli: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-heli"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Kuuldeaparaadid"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Kuuldeaparaatidega ühendatud"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ühendatud üksusega LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ühendatud meediumiheliga"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ühendatud telefoniheliga"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Kasuta telefoniheli jaoks"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Kasutage failide edastamiseks"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Kasutage sisendi jaoks"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Kasutatakse kuuldeaparaatide puhul"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Üksuse LE_AUDIO kasutamine"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Seo"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SEO"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Praegusi puuteandmeid kuvav ekraani ülekate"</string>
<string name="show_touches" msgid="8437666942161289025">"Kuva puudutused"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Kuvab puudutuste visuaalse tagasiside"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Kuva klahvivajutused"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Kuva visuaalset tagasisidet füüsiliste klahvivajutuste kohta"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Näita pinna värskendusi"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Akna pinna värskendamiseks kirjuta kogu akna pind üle"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Kuva ekraanikuva värskendusi"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index fcb6fd1..93abed2 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIMerako sarbidea"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Kalitate handiko audioa: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Kalitate handiko audioa"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audifonoak"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Kontsumo txikiko Bluetooth bidezko audioa"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Audifonoetara konektatuta"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audio-ra konektatuta"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Euskarriaren audiora konektatuta"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefonoaren audiora konektatuta"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Erabili telefonoaren audiorako"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Erabili fitxategi-transferentziarako"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Erabili idazketarako"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Erabili audifonoekin"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Erabili LE_AUDIO-rako"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parekatu"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREKATU"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ukipen-datuak erakusteko pantaila-gainjartzea"</string>
<string name="show_touches" msgid="8437666942161289025">"Erakutsi sakatutakoa"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Erakutsi sakatutako elementuak"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Erakutsi tekla-sakatzeak"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Erakutsi sakatutako tekla fisikoak"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Erakutsi azaleko aldaketak"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Distirarazi leiho osoen azalak haiek eguneratzean"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Erakutsi ikuspegi-aldaketak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 8daf78a..33d262f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"دسترسی سیمکارت"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"صدای HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"صدای HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"سمعک"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"صدای کممصرف"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"متصل به سمعک"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"به «صدای کممصرف» وصل است"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"به رسانه صوتی متصل شد"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"به تلفن صوتی متصل شد"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"استفاده برای تلفن صوتی"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"استفاده برای انتقال فایل"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"استفاده برای چاپ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"استفاده برای سمعک"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"استفاده برای LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"مرتبطسازی"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"مرتبطسازی"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"همپوشانی صفحهنمایش با نمایش داده لمسی فعلی"</string>
<string name="show_touches" msgid="8437666942161289025">"نمایش ضربهها"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"نمایش بازخورد تصویری برای ضربهها"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"نمایش فشار کلیدها"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"نمایش بازخورد بصری برای فشار دادن کلیدهای فیزیکی"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"نمایش بهروزرسانی سطح"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"هنگام بهروزرسانی سطوح پنجره همه فلش شوند"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"نمایش بهروزرسانیهای نما"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index b469cbc..6ac22b2 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-kortin käyttö"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ääni: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ääni"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Kuulolaitteet"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Yhdistetty kuulolaitteisiin"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio yhdistetty"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Yhdistetty median ääneen"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Yhdistetty puhelimen ääneen"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Käytä puhelimen äänille"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Käytä tiedostojen siirtoon"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Käytä syöttöön"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Käytä kuulolaitteilla"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Käyttö: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Muodosta laitepari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"MUODOSTA LAITEPARI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Näytön peittokuva näyttää nykyiset kosketustiedot"</string>
<string name="show_touches" msgid="8437666942161289025">"Näytä kosketus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Anna visuaalista palautetta kosketuksesta"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Näytä näppäinpainallukset"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Näytä visuaalista palautetta näppäinpainalluksista"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Näytä pintapäivitykset"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Väläytä koko ikkunoiden pinnat päivitettäessä"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Näytä näyttöpäivitykset"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 06d8373..532374da 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accès à la carte SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Prothèses auditives"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connecté aux prothèses auditives"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté par LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté à l\'audio du téléphone"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utiliser pour les paramètres audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utiliser pour le transfert de fichiers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utiliser comme entrée"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Utiliser avec les prothèses auditives"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utiliser pour LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Associer"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ASSOCIER"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposition écran indiquant données actuelles"</string>
<string name="show_touches" msgid="8437666942161289025">"Afficher éléments sélect."</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afficher repère visuel pour éléments sélectionnés"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Afficher press. de touches"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Afficher retour visuel pour press. de touches phys."</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Afficher mises à jour surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Faire clignoter les surfaces à chaque mise à jour"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Afficher m. à j. affichage"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b4791ff..683cfa5 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accès à la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Appareils auditifs"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connexion établie avec les appareils auditifs"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté à LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté aux paramètres audio du téléphone"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utiliser pour les paramètres audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utiliser pour le transfert de fichiers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utiliser comme entrée"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Utiliser pour les appareils auditifs"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utiliser pour LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Associer"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ASSOCIER"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposition à l\'écran indiquant l\'emplacement actuel du curseur"</string>
<string name="show_touches" msgid="8437666942161289025">"Indicateurs visuels"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afficher un indicateur visuel là où l\'utilisateur appuie sur l\'écran"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Afficher appuis touche"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Afficher retour visuel pour appuis de touches"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mises à jour de la surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Faire clignoter les endroits où des mises à jour sont effectuées"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mises à jour de fenêtres"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index c151db8..0661d7a 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso á SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audiófonos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Audio de baixo consumo"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectado a audiófonos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Estableceuse conexión co audio de baixo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao audio do teléfono"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilízase para o audio do teléfono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilízase para a transferencia de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilízase para a entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Úsase para audiófonos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usa esta opción para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincular"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"VINCULAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superpón os datos dos toques na pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra a localización dos toques na pantalla"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostrar teclas premidas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostra información das teclas físicas premidas"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ilumina as superficies de ventás ao actualizarse"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mostrar actualizacións"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 914645e..b92d2f2 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"સિમ ઍક્સેસ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ઑડિયો: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ઑડિયો"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"સાંભળવામાં મદદ આપતા યંત્રો"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ઑડિયો"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"સાંભળવામાં મદદ આપતા યંત્રો સાથે કનેક્ટ કરેલું છે"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ઑડિયોથી કનેક્ટેડ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"મીડિયા ઑડિઓ સાથે કનેક્ટ કર્યુ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ફોન ઑડિઓ સાથે કનેક્ટ થયાં"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ફોન ઑડિઓ માટે ઉપયોગ કરો"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ફાઇલ સ્થાનાંતર માટે ઉપયોગ કરો"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ઇનપુટ માટે ઉપયોગ કરો"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"સાંભળવામાં મદદ આપતા યંત્રો માટે ઉપયોગ કરો"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO માટે ઉપયોગ કરો"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"જોડી કરો"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"જોડી કરો"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"વર્તમાન ટચ ડેટા દર્શાવતું સ્ક્રીન ઓવરલે"</string>
<string name="show_touches" msgid="8437666942161289025">"ટૅપ બતાવો"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ટૅપ માટે વિઝ્યુઅલ પ્રતિસાદ બતાવો"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"કી દબાવવાની ઘટના બતાવો"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"વાસ્તિવક રીતે કી દબાવવાના વિઝ્યુઅલ પ્રતિસાદ બતાવો"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"સપાટી અપડેટ બતાવો"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"તે અપડેટ થાય ત્યારે સમગ્ર વિન્ડો સપાટી ફ્લેશ કરો"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"વ્યૂના અપડેટ બતાવો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index f2b7ea1..21936c8 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"सिम ऐक्सेस"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"एचडी ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"एचडी ऑडियो"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"कान की मशीनें"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"कान की मशीनों के साथ कनेक्ट किया गया"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio से कनेक्ट किया गया"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडियो से कनेक्ट किया गया"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फ़ोन ऑडियो से कनेक्ट किया गया"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फ़ोन ऑडियो के लिए उपयोग करें"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फ़ाइल स्थानांतरण के लिए उपयोग करें"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुट के लिए उपयोग करें"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"कान की मशीनों के लिए इस्तेमाल करें"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO के लिए इस्तेमाल करें"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"जोड़ें"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"जोड़ें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 559fd73..7a8507d 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM-u"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Slušna pomagala"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Povezano sa slušnim pomagalima"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE_AUDIO"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano s medijskim zvukom"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa telefonskim zvukom"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Koristi za telefonski zvuk"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Koristi za prijenos datoteke"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Upotrijebi za ulaz"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Upotrijebi za slušna pomagala"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Upotrebljavajte za LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Na zaslonu se prikazuju podaci o dodirima"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikazuju se vizualne povratne informacije za dodire"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Prikaži pritiske na tipke"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Prikaži vizualne povratne informacije za pritiske na tipke"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Sve površine prozora bljeskaju pri ažuriranju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 2607e2d..a67748f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-elérés"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hallókészülék"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Alacsony energiaszintű hangátvitel"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Hallókészülékhez csatlakoztatva"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Csatlakoztatva az alacsony energiaszintű hangátvitelhez"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Csatlakoztatva az eszköz hangjához"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Csatlakoztatva a telefon hangjához"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Felhasználás a telefon hangjához"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Felhasználás fájlátvitelre"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Használat beviteli eszközként"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Hallókészülékkel való használat"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Használat ehhez: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Párosítás"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PÁROSÍTÁS"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"A fedvény mutatja az aktuális érintési adatokat"</string>
<string name="show_touches" msgid="8437666942161289025">"Koppintások megjelenítése"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Koppintások vizuális visszajelzésének megjelenítése"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Gomblenyomások mutatása"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Fizikai gomblenyomások vizuális visszajelzéseinek mutatása"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Felületfrissítések megj."</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"A teljes ablakfelület villogjon frissítéskor."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Frissítések megjelenítése"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index c95fb57..b72b094 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM քարտի հասանելիություն"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD աուդիո՝ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD աուդիո"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Լսողական սարք"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Միացված է լսողական սարքին"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Միացած է LE audio-ին"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Միացված է մեդիա աուդիոյին"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Միացված է հեռախոսի ձայնային տվյալներին"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Օգտագործել հեռախոսի աուդիոյի համար"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Օգտագործել ֆայլի փոխանցման համար"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Օգտագործել ներմուծման համար"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Օգտագործել լսողական սարքի համար"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Օգտագործել LE_AUDIO-ի համար"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Զուգակցել"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"Զուգակցել"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ հպման տվյալները"</string>
<string name="show_touches" msgid="8437666942161289025">"Ցույց տալ հպումները"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ցույց տալ հպումների տեսանելի արձագանքը"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Ցույց տալ սեղմումները"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Տեսողական արձագանք ստեղների սեղմումների համար"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Ցույց տալ մակերեսի թարմացումները"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Թարմացվելիս ընդգծել սարքաշարի ծածկույթները կանաչ գույնով"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ցուցադրել թարմացումները"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index a56a479..07dd53a 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Akses SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Alat bantu dengar"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Terhubung ke alat bantu dengar"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Terhubung ke LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Terhubung ke media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Terhubung ke audio ponsel"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gunakan untuk audio ponsel"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk transfer file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk masukan"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Gunakan untuk alat bantu dengar"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Digunakan untuk LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sambungkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAMBUNGKAN"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay layar menampilkan data sentuhan saat ini"</string>
<string name="show_touches" msgid="8437666942161289025">"Tampilkan ketukan"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan efek visual untuk ketukan"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Tampilkan penekanan tombol"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Tampilkan respons visual untuk penekanan tombol fisik"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Tampilkan pembaruan permukaan"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Buat seluruh permukaan jendela berkedip saat diperbarui"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Tampilkan pembaruan tampilan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 0928d72..bb7bf70 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Aðgangur að SIM-korti"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-hljóð: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-hljóð"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Heyrnartæki"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-hljóð"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Tengt við heyrnartæki"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Tengt við LE-hljóð"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Tengt við hljóðspilun efnis"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Tengt við hljóð símans"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Nota fyrir hljóð símans"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Nota við skráaflutning"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Nota fyrir inntak"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Nota fyrir heyrnartæki"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Nota fyrir LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Para"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PARA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skjáyfirlögn sem sýnir rauntímagögn um snertingar"</string>
<string name="show_touches" msgid="8437666942161289025">"Sýna snertingar"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Sýna snertingar myndrænt"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Sýna „Ýtt á lykil“"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Sýna myndsvörun fyrir „Ýtt á raunverulegan lykil“"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Sýna yfirborðsuppfærslur"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Láta allt yfirborð glugga blikka við uppfærslu"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Sýna uppfærslur yfirlits"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index ae19c41..5926a6b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accesso alla SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Apparecchi acustici"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connessione con gli apparecchi acustici stabilita"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connesso a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Collegato ad audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Collegato ad audio telefono"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usa per audio telefono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usa per trasferimento file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizza per l\'input"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Utilizza per gli apparecchi acustici"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usa per LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Accoppia"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ACCOPPIA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay schermo che mostra i dati touch correnti"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostra tocchi"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra feedback visivi per i tocchi"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostra pressioni tasti"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostra feedback visivo per pressioni tasti fisici"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Aggiornamenti superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fai lampeggiare le superfici delle finestre quando si aggiornano"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Aggiornam. visualizzazione"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 6ba7aa4..51bda70 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"גישה ל-SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"אודיו באיכות HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"אודיו באיכות HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"מכשירי שמיעה"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"מחובר למכשירי השמיעה"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"מחובר אל LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"מחובר לאודיו של מדיה"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"מחובר לאודיו של הטלפון"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"השתמש עבור האודיו של הטלפון"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"לצורך העברת קבצים"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"שימוש כקלט"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"שימוש למכשירי שמיעה"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"לשימוש עבור LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"התאמה"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"התאמה"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"שכבת-על של המסך המציגה את נתוני המגע הנוכחיים"</string>
<string name="show_touches" msgid="8437666942161289025">"הצגת הקשות"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"הצגת משוב ויזואלי להקשות"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"הצגת לחיצות המקשים"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"הצגת משוב חזותי עבור לחיצות פיזיות על מקשים"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"הצגת עדכונים על פני השטח"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"הבהוב של כל שטחי החלון כשהם מתעדכנים"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"הצגת עדכונים של התצוגה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a4230fc..d15b4ef 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIMアクセス"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD オーディオ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD オーディオ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"補聴器"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"補聴器に接続"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio に接続"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"メディアの音声に接続"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"携帯電話の音声に接続"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"携帯電話の音声に使用"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ファイル転送に使用"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"入力に使用"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"補聴器に使用"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO の使用"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ペア設定する"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ペア設定する"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"現在のタップデータをオーバーレイ表示する"</string>
<string name="show_touches" msgid="8437666942161289025">"タップを表示"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"タップを視覚表示する"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"キーの押下を表示"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"物理キーの押下に関する視覚的フィードバックを表示"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"表示面の更新を通知"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"更新時にウィンドウの表示面全体を点滅させる"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"画面の更新を表示"</string>
@@ -552,12 +547,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"このデバイス"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"このタブレット"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"このデバイス"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"このデバイスでは再生できません"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"アカウントを更新して切り替えてください"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 50447d7..f63d4c2 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM წვდომა"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD აუდიო: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD აუდიო"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"სმენის მოწყობილობები"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-აუდიო"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"დაკავშირებულია სმენის მოწყობილობებთან"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"დაკავშირებულია LE აუდიოსთან"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"დაკავშირებულია აუდიო მულტიმედიურ სისტემასთან"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"დაკავშირებულია ტელეფონის აუდიო მოწყობილობასთან"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"გამოიყენეთ ტელეფონის აუდიომოწყობილობაში"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ფაილების ტრანსფერისათვის გამოყენება"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"შეტანისთვის გამოყენება"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"გამოყენება სმენის მოწყობილობებისთვის"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"გამოიყენება შემდეგისთვის: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"დაწყვილება"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"დაწყვილება"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ეკრანის გადაფარვა შეხების მონაცემების ჩვენებით"</string>
<string name="show_touches" msgid="8437666942161289025">"შეხებების ჩვენება"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"შეხებებისთვის ვიზუალური უკუკავშირის ჩვენება"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"კლავიშების დაჭერის ჩვენება"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ვიზუალური გამოხმაურების ჩვენება კლავიშის დაჭერაზე"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"ზედაპირის განახლებების ჩვენება"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ფანჯრის მთელი ზედაპირის აციმციმება მისი განახლებისას"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"განახლებების ჩვენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index d57bedb..883dea6 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM картасына кіру"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD форматты аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD форматты аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Есту аппараттары"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Есту аппараттарына жалғанған"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio-ға жалғанды."</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиосына жалғанған"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосына қосылған"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Телефон аудиосы үшін қолдану"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файлды жіберу үшін қолдану"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Кіріс үшін қолдану"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Есту аппараттары үшін пайдалану"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO үшін пайдалану"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Жұптау"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ЖҰПТАУ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Экран бетіне түртілген элемент дерегі көрсетіледі"</string>
<string name="show_touches" msgid="8437666942161289025">"Түрту қимылын көрсету"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Түрту қимылын экраннан көрсету"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Түйменің басылуын көрсету"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Түйменің басылуын экраннан көрсету"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Бедердің жаңарғанын көрсету"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Бедері жаңарғанда, терезені түгелдей жыпылықтату"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Көріністің жаңарғанын көрсету"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index a3f9ac8..f7a8bfd 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ការចូលដំណើរការស៊ីម"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"សំឡេងកម្រិត HD៖ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"សំឡេងកម្រិត HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"បានភ្ជាប់ទៅឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"បានភ្ជាប់ទៅ LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"បានភ្ជាប់ទៅអូឌីយ៉ូមេឌៀ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"តភ្ជាប់ទៅអូឌីយ៉ូទូរស័ព្ទ"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ប្រើសម្រាប់អូឌីយ៉ូទូរស័ព្ទ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ប្រើសម្រាប់ផ្ទេរឯកសារ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ប្រើសម្រាប់បញ្ចូល"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ប្រើសម្រាប់ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"ប្រើសម្រាប់ LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ផ្គូផ្គង"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ផ្គូផ្គង"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"អេក្រង់ត្រួតគ្នាបង្ហាញទិន្នន័យប៉ះបច្ចុប្បន្ន"</string>
<string name="show_touches" msgid="8437666942161289025">"បង្ហាញការចុច"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"បង្ហាញដានចុច នៅពេលចុច"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"បង្ហាញការចុចគ្រាប់ចុច"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"បង្ហាញព័ត៌មានឆ្លើយតបជារូបភាពសម្រាប់ការចុចគ្រាប់ចុចរូបវន្ត"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"បង្ហាញបច្ចុប្បន្នភាពផ្ទៃ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ផ្ទៃវីនដូទាំងមូលបញ្ចេញពន្លឺនៅពេលធ្វើបច្ចុប្បន្នភាព"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"បង្ហាញបច្ចុប្បន្នភាពទិដ្ឋភាព"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 70ca323..e29e22b 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ಸಿಮ್ ಆ್ಯಕ್ಸೆಸ್"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ಆಡಿಯೋ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ಆಡಿಯೋ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ಆಡಿಯೋ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ಶ್ರವಣ ಸಾಧನಗಳಿಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ಆಡಿಯೋಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ಮಾಧ್ಯಮ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ಫೋನ್ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ಫೋನ್ ಆಡಿಯೋಗಾಗಿ ಬಳಕೆ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ಫೈಲ್ ವರ್ಗಾವಣೆಗಾಗಿ ಬಳಸು"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ಇನ್ಪುಟ್ಗಾಗಿ ಬಳಸು"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ಶ್ರವಣ ಸಾಧನಗಳಿಗಾಗಿ ಬಳಸಿ"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO ಗೆ ಬಳಸಿ"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ಜೋಡಿಸಿ"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ಜೋಡಿ ಮಾಡು"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ಪ್ರಸ್ತುತ ಸ್ಪರ್ಶ ಡೇಟಾ ತೋರಿಸುವ ಪರದೆಯ ಓವರ್ಲೇ"</string>
<string name="show_touches" msgid="8437666942161289025">"ಟ್ಯಾಪ್ಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ಟ್ಯಾಪ್ಗಳಿಗೆ ದೃಶ್ಯ ಪ್ರತಿಕ್ರಿಯೆ ತೋರಿಸು"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"ಕೀ ಪ್ರೆಸ್ಗಳನ್ನು ತೋರಿಸಿ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ಭೌತಿಕ ಕೀ ಪ್ರೆಸ್ಗಳ ವಿಷುವಲ್ ಪ್ರತಿಕ್ರಿಯೆಗಾಗಿ ನೋಡಿ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"ಸರ್ಫೇಸ್ ಅಪ್ಡೇಟ್ ತೋರಿಸಿ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ಅಪ್ಡೇಟ್ ಆಗುವಾಗ ವಿಂಡೋದ ಸರ್ಫೇಸ್ ಫ್ಲ್ಯಾಶ್ ಆಗುತ್ತದೆ"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"\'ಅಪ್ಡೇಟ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ\' ತೋರಿಸಿ"</string>
@@ -531,7 +526,7 @@
<string name="back" msgid="5554327870352703710">"ಹಿಂದಕ್ಕೆ"</string>
<string name="save" msgid="3745809743277153149">"ಉಳಿಸಿ"</string>
<string name="okay" msgid="949938843324579502">"ಸರಿ"</string>
- <string name="done" msgid="381184316122520313">"ಮುಗಿದಿದೆ"</string>
+ <string name="done" msgid="381184316122520313">"ಆಯಿತು"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ಅಲಾರಾಮ್ಗಳು ಮತ್ತು ರಿಮೈಂಡರ್ಗಳು"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್ಗಳನ್ನು ಹೊಂದಿಸಲು ಅನುಮತಿಸಿ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್ಗಳು"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 32f86a1..653ac23 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM 액세스"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 오디오: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 오디오"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"보청기"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE 오디오"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"보청기에 연결됨"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE 오디오에 연결됨"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"미디어 오디오에 연결됨"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"휴대전화 오디오에 연결됨"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"휴대전화 오디오에 사용"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"파일 전송에 사용"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"입력에 사용"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"보청기로 사용"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO에 사용"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"페어링"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"페어링"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"현재 터치 데이터 오버레이 표시"</string>
<string name="show_touches" msgid="8437666942161289025">"탭한 항목 표시"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"탭한 항목에 대해 시각적인 피드백 표시"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"키 누름 표시"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"물리적 키 누름에 관한 시각적 피드백을 표시합니다."</string>
<string name="show_screen_updates" msgid="2078782895825535494">"표면 업데이트 표시"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"전체 창 화면이 업데이트되었을 때 플래시 처리"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"보기 업데이트 표시"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 111b804..c2aa652 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM картаны пайдалануу мүмкүнчүлүгү"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD форматындагы аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD форматындагы аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Угуу аппараттары"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Угуу аппараттарына туташып турат"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудио менен туташты"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиого туташты"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосуна туташты"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Телефон аудиосу үчүн колдонулсун"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файл өткөрүү үчүн колдонулсун"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Киргизүү үчүн колдонулсун"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Угуу аппараттары үчүн колдонуу"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO үчүн колдонуу"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Байланыштыруу"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ЖУПТАШТЫРУУ"</string>
@@ -262,7 +259,7 @@
<string name="keep_screen_on" msgid="1187161672348797558">"Ойгоо туруу"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"Түзмөк кубатталып жатканда экран өчпөйт"</string>
<string name="bt_hci_snoop_log" msgid="7291287955649081448">"Bluetooth HCI журналын иштетүү"</string>
- <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Bluetooth таңгактарын алуу. (Бул жөндөөнү өзгөрткөндөн кийин Bluetooth\'ду өчүрүп / күйгүзүңүз)"</string>
+ <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Bluetooth таңгактарын алуу. (Бул параметрди өзгөрткөндөн кийин Bluetooth\'ду өчүрүп / күйгүзүңүз)"</string>
<string name="oem_unlock_enable" msgid="5334869171871566731">"OEM бөгөттөн чыгаруу"</string>
<string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Кайра жүктөгүчтү бөгөттөн чыгарууга уруксат берүү"</string>
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM бөгөттөн чыгарууга уруксатпы?"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Басылган жерлер жана жаңсоолор экранда көрүнүп турат"</string>
<string name="show_touches" msgid="8437666942161289025">"Басылган жерлерди көрсөтүү"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Экранда басылган жерлер көрүнүп турат"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Баскычтардын басылганын көрсөтүү"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Баскычтар басылганда визуалдык сигнал көрүнөт"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Экран жаңыруусун көрсөтүү"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Экран жаңырганда анын үстү жарык болот"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Жаңыртууларды көрсөтүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index beca19e..0a429fd 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ການເຂົ້າເຖິງ SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"ສຽງ HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"ສຽງ HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ເຄື່ອງຊ່ວຍຟັງ"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"ສຽງ LE"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ເຊື່ອມຕໍ່ກັບເຄື່ອງຊ່ວຍຟັງແລ້ວ"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ເຊື່ອມຕໍ່ຫາສຽງ LE ແລ້ວ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ເຊື່ອມຕໍ່ກັບສື່ດ້ານສຽງແລ້ວ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ເຊື່ອມຕໍ່ກັບສຽງໂທລະສັບແລ້ວ"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ໃຊ້ສຳລັບລະບົບສຽງຂອງໂທລະສັບ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ໃຊ້ເພື່ອໂອນຍ້າຍໄຟລ໌"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ໃຊ້ສຳລັບການປ້ອນຂໍ້ມູນ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ໃຊ້ສຳລັບເຄື່ອງຊ່ວຍຟັງ"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"ໃຊ້ສຳລັບ LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ຈັບຄູ່"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ຈັບຄູ່"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ການວາງຊ້ອນໜ້າຈໍກຳລັງສະແດງຂໍ້ມູນການສຳຜັດໃນປັດຈຸບັນ"</string>
<string name="show_touches" msgid="8437666942161289025">"ສະແດງການແຕະ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ສະແດງຄໍາຕິຊົມທາງຮູບພາບສຳລັບການແຕະ"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"ສະແດງການກົດປຸ່ມ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ສະແດງຄຳຕິຊົມພາບສຳລັບການກົດປຸ່ມຈິງ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"ສະແດງການອັບເດດພື້ນຜິວ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ກະພິບໜ້າຈໍທັງໜ້າເມື່ອມີການອັບເດດ"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"ສະແດງອັບເດດມຸມມອງ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 6307ff3..78246dc 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM prieiga"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD garsas: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD garsas"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Klausos aparatai"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Prisijungta prie klausos aparatų"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Prisijungta prie „LE Audio“"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Prijungta prie medijos garso įrašo"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Prijungta prie telefono garso"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Naudoti telefono garso įrašui"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Naudoti failų perkėlimui"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Naudoti įvedant"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Naudoti su klausos aparatais"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Naudoti LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Susieti"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SUSIETI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekrano perdanga rodo dabartinius lietimo duomenis"</string>
<string name="show_touches" msgid="8437666942161289025">"Rodyti palietimus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Rodyti vaizdinius palietimų atsiliepimus"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Rodyt klavišų paspaudimus"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Rodyti fizinių klavišų paspaudimų vaizdinį atsiliepimą"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Rodyti paviršiaus naujin."</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Naujinant mirginti visus langų paviršius"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Rodyti rodinių naujinius"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 880d7a4..e3fbcdf 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Piekļuve SIM kartei"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Dzirdes aparāti"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Izveidots savienojums ar dzirdes aparātiem"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Izveidots savienojums ar LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Savienots ar multivides audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Savienots ar tālruņa audio"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Izmantot tālruņa skaņai"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Izmantot faila pārsūtīšanai"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Izmantot ievadei"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Izmantot dzirdes aparātiem"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Izmantot LE_AUDIO profilam"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Izveidot pāri"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAVIENOT PĀRĪ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekrāna pārklājums ar aktuāliem pieskāriena datiem"</string>
<string name="show_touches" msgid="8437666942161289025">"Rādīt pieskārienus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Rādīt vizuālo reakciju pēc pieskārieniem"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Rādīt taustiņu nospiešanu"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Vizuāla reakcija uz fizisku taustiņu nospiešanu"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Rādīt virsmas atjauninājumus WL: 294"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Atjaunināt visa loga virsmas, kad tās tiek atjauninātas WL: 294"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Rādīt skat. atjaunin."</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 7362c67..6ba8d5c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Пристап до SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слушни помагала"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-аудио"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Поврзано со слушни помагала"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Поврзано на LE-аудио"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Поврзан со аудио на медиуми"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Поврзан со аудио на телефон"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Користи за аудио на телефон"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Користи за пренос на датотеки"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Користи за внес"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Користам слушни помагала"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Користи за LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Спари"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"СПАРИ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Прекривката на екран ги покажува тековните податоци на допир"</string>
<string name="show_touches" msgid="8437666942161289025">"Прикажувај допири"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Прикажувај визуелни повратни информации за допири"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Прикаж. притисн. копчиња"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Визуелно го прикажува притискањето на копчињата"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Прикажи ажурир. површина"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Осветли површ. на прозорци при нивно ажурирање"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Покажувај ажурирања на приказот"</string>
@@ -476,7 +471,7 @@
<string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Уредот може да се исклучи наскоро (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полна батерија"</string>
- <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string>
+ <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е оптимизирано"</string>
<string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е оптимизирано"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1e7ef2b..0f4d30d 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"സിം ആക്സസ്"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ഓഡിയോ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ഓഡിയോ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ശ്രവണ സഹായികൾ"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ഓഡിയോ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ശ്രവണ സഹായികളിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ഓഡിയോയിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"മീഡിയ ഓഡിയോയിലേക്ക് കണക്റ്റുചെയ്തു"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ഫോൺ ഓഡിയോയിൽ കണക്റ്റുചെയ്തു"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ഫോൺ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ഫയൽ കൈമാറ്റത്തിനായി ഉപയോഗിക്കുന്നു"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ഇൻപുട്ടിനായി ഉപയോഗിക്കുക"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ശ്രവണ സഹായികൾക്കായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO ഉപയോഗിക്കുക"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ജോടിയാക്കുക"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ജോടിയാക്കുക"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"സ്ക്രീൻ ഓവർലേ നിലവിലെ ടച്ച് ഡാറ്റ ദൃശ്യമാക്കുന്നു"</string>
<string name="show_touches" msgid="8437666942161289025">"ടാപ്പുകൾ കാണിക്കുക"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ടാപ്പുകൾക്ക് ദൃശ്യ ഫീഡ്ബാക്ക് കാണിക്കുക"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"കീ അമർത്തലുകൾ കാണിക്കുക"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ഫിസിക്കൽ കീ അമർത്തൽ വിഷ്വൽ ഫീഡ്ബാക്ക് കാണിക്കൂ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"സർഫേസ് അപ്ഡേറ്റ് കാണിക്കൂ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"അപ്ഡേറ്റ് പൂർത്തിയാകുമ്പോൾ മുഴുവൻ വിൻഡോ സർഫേസുകളും ഫ്ലാഷ് ചെയ്യുക"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"\'അപ്ഡേറ്റുകൾ കാണുക\' കാണിക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index a77c07f..29fb6d4 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM Хандалт"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD аудио"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Сонсголын төхөөрөмж"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Аудио"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Сонсголын төхөөрөмжтэй холбосон"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудионд холбогдсон"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиод холбогдсон"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Утасны аудид холбогдсон"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Утасны аудиод ашиглах"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файл дамжуулахад ашиглах"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Оруулахад ашиглах"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Сонсголын төхөөрөмж болгон ашиглах"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_АУДИОНД ашиглах"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Хослуулах"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ХОСЛУУЛАХ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Дэлгэцийн давхаргаар одоогийн хүрэлтийн өгөгдлийг харуулж байна"</string>
<string name="show_touches" msgid="8437666942161289025">"Товшилтыг харуулах"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Товшилтын визуал хариу үйлдлийг харуулах"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Түлхүүрийн даралт харуул"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Биет түлхүүрийн даралтын визуал санал хүсэлт харуул"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Гадаргын шинэчлэлтүүдийг харуулах"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Шинэчлэгдэх үед цонхны гадаргыг бүхэлд нь анивчуулах"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Шинэчлэлт харахыг харуулах"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 0d62281..e9e0ee4 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"सिम अॅक्सेस"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ऑडिओ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ऑडिओ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"श्रवणयंत्रे"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ऑडिओ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"श्रवणयंत्रांशी कनेक्ट केले आहे"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ऑडिओशी कनेक्ट केले आहे"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडिओवर कनेक्ट केले"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन ऑडिओ वर कनेक्ट केले"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फोन ऑडिओसाठी वापरा"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फाइल स्थानांतरणासाठी वापरा"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुट साठी वापरा"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"श्रवणयंत्रांसाठी वापरा"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO साठी वापरले आहे"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"पेअर करा"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"पेअर करा"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"वर्तमान स्पर्श डेटा दर्शविणारे स्क्रीन ओव्हरले"</string>
<string name="show_touches" msgid="8437666942161289025">"टॅप दाखवा"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"टॅपसाठी व्हिज्युअल फीडबॅक दाखवा"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"की प्रेस दाखवा"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"प्रत्यक्ष की प्रेससाठी व्हिज्युअल फीडबॅक दाखवा"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"सर्फेस अपडेट दाखवा"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"संपूर्ण विंडो सर्फेस अपडेट होतात तेव्हा ते फ्लॅश करा"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"व्ह्यू अपडेट दाखवा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 83326c7..0a41c0f 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Akses SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Alat bantu pendengaran"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Disambungkan kepada alat bantu pendengaran"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Disambungkan kepada LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Disambungkan ke audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Disambungkan ke audio telefon"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gunakan untuk audio telefon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk pemindahan fail"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk input"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Gunakan untuk alat bantu pendengaran"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gunakan untuk LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Gandingkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"JADIKAN PASANGAN"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Tindihan skrin menunjukkan data sentuh semasa"</string>
<string name="show_touches" msgid="8437666942161289025">"Tunjukkan ketikan"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Tunjukkan maklum balas visual untuk ketikan"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Tunjukkan tekanan kekunci"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Tunjukkan maklum balas visual untuk tekanan kekunci fizikal"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Tunjuk kemaskinian permukaan"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Denyar permukaan tetingkap apabila dikemas kini"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Tunjuk kemaskinian paparan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 049354e..7346d91 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"လက်ရှိထိတွေ့မှုဒေတာကို ဖန်သားပေါ်တွင်ထပ်၍ ပြသသည်"</string>
<string name="show_touches" msgid="8437666942161289025">"တို့ခြင်းများကို ပြပါ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"တို့ခြင်းများအတွက် အမြင်ဖြင့် တုံ့ပြန်မှုပြသည်"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"ကီးနှိပ်မှုများ ပြပါ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ပကတိကီးနှိပ်မှုများအတွက် ရုပ်မြင်အကြံပြုချက် ပြပါ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"မျက်နှာပြင်အပ်ဒိတ်ပြရန်"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"အပ်ဒိတ်လုပ်စဉ် ဝင်းဒိုးမျက်နှာပြင်တွင် အချက်ပြရန်"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"မြင်ကွင်းအပ်ဒိတ်များ ပြခြင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 16054fc..dc68bf3 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Tilgang til SIM-kortet"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Høreapparater"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-lyd"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Koblet til høreapparater"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Koblet til LE-lyd"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Koblet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Koblet til telefonlyd"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Bruk for telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Bruk til filoverføring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Bruk for inndata"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Bruk for høreapparater"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Bruk for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koble til"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOBLE TIL"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skjermoverlegg viser aktuelle berøringsdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Vis trykk"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vis visuell tilbakemelding for trykk"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Vis tastetrykk"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Vis visuell tilbakemelding for fysiske tastetrykk"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Vis overflateoppdateringer"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fremhev hele vindusoverflater når de oppdateres"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Vis visningsoppdateringer"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 1d0b790..5d61132 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM एक्सेस"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD अडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD अडियो"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"श्रवण यन्त्रहरू"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE अडियो"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"श्रवण यन्त्रहरूमा जडान गरियो"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE अडियोमा कनेक्ट गरिएको छ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मिडिया अडियोसँग जडित"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन अडियोमा जडान गरियो"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फोन अडियोको लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फाइल ट्रान्सफरका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुटको लागि प्रयोग गर्नुहोस्"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"श्रवण यन्त्रहरूका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO मा प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"कनेक्ट गर्नुहोस्"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"जोडी"</string>
@@ -323,9 +320,9 @@
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Wi-Fi अन हुँदा पनि मोबाइल डेटा सधैँ अन होस् (द्रुत रूपमा नेटवर्क बदल्न)।"</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"उपलब्ध हुँदा टेदरिङ हार्डवेयर एक्सलरेसन प्रयोग गरियोस्"</string>
<string name="adb_warning_title" msgid="7708653449506485728">"USB डिबग गर्न लागि अनुमति दिने हो?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"युएसबी डिबगिङ विकास प्रयोजनका लागि मात्र निर्मित हुन्छ। यसलाई तपाईँको कम्प्युटर र तपाईँको उपकरणका बीच डेटा प्रतिलिपि गर्न, बिना सूचना तपाईँको उपकरणमा एपहरू इन्स्टल गर्न र लग डेटा पढ्नका लागि प्रयोग गर्नुहोस्।"</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"युएसबी डिबगिङ विकास प्रयोजनका लागि मात्र निर्मित हुन्छ। यसलाई तपाईँको कम्प्युटर र तपाईँको उपकरणका बीच डेटा कपी गर्न, बिना सूचना तपाईँको उपकरणमा एपहरू इन्स्टल गर्न र लग डेटा पढ्नका लागि प्रयोग गर्नुहोस्।"</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"वायरलेस डिबगिङ सेवा सक्षम पार्ने हो?"</string>
- <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डिबगिङ डिभलपमेन्ट प्रयोजनका लागि मात्रै हो। यसलाई आफ्ना कम्प्युटर र उपकरणका बिच डेटा प्रतिलिपि गर्न, सूचना नदिई आफ्नो उपकरणमा एपहरू इन्स्टल गर्न र लग डेटा पढ्न प्रयोग गर्नुहोस्।"</string>
+ <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डिबगिङ डिभलपमेन्ट प्रयोजनका लागि मात्रै हो। यसलाई आफ्ना कम्प्युटर र उपकरणका बिच डेटा कपी गर्न, सूचना नदिई आफ्नो उपकरणमा एपहरू इन्स्टल गर्न र लग डेटा पढ्न प्रयोग गर्नुहोस्।"</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"तपाईं पहिले नै अधिकृत गर्नुभएका सबै कम्प्यूटरबाट USB डिबग गर्नको लागि पहुँच रद्द गर्ने हो?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"विकास सेटिङहरू अनुमति दिने हो?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"यी सेटिङहरू केवल विकास प्रयोगको लागि विचार गरिएको हो। तिनीहरूले तपाईंको उपकरण र एपहरूलाई विच्छेदन गर्न वा दुर्व्यवहार गर्न सक्दछ।"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"स्क्रिन ओभरलेले हालको टच डेटा देखाउँदै छ"</string>
<string name="show_touches" msgid="8437666942161289025">"ट्याप देखाइयोस्"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ट्यापका लागि भिजुअल प्रतिक्रिया देखाइयोस्"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"थिचिएका कीहरू देखाइयून्"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"थिचिएका भौतिक कीसम्बन्धी भिजुअल प्रतिक्रिया देखाइयोस्"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"सर्फेस अपडेट देखाइयोस्"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"अपडेट हुँदा विन्डोका पूरै सतहमा देखाइयोस्"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"GPU भ्युको अपडेट देखाइयोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 3287711..51fc99a2 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Sim-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hoortoestellen"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Verbonden met hoortoestellen"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Verbonden met LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbonden met audio van medium"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbonden met audio van telefoon"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruiken voor audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruiken voor bestandsoverdracht"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruiken voor invoer"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Gebruiken voor hoortoestellen"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gebruiken voor LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppelen"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELEN"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Schermoverlay met huidige aanraakgegevens"</string>
<string name="show_touches" msgid="8437666942161289025">"Tikken tonen"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Toon visuele feedback voor tikken"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Toetsaanslagen tonen"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Visuele feedback tonen voor fysieke toetsaanslagen"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Oppervlakupdates tonen"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash volledige vensteroppervlakken bij updates"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Weergave-updates tonen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index a78681e..22f923d 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM ଆକ୍ସେସ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ଅଡିଓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ଅଡିଓ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ଅଡିଓ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ଶ୍ରବଣ ଯନ୍ତ୍ର ସହ କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ଅଡିଓ ସହ କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ମିଡିଆ ଅଡିଓ ସହ ସଂଯୁକ୍ତ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ଫୋନ୍ ଅଡିଓ ସହିତ ସଂଯୁକ୍ତ"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ଫୋନ୍ ଅଡିଓ ପାଇଁ ବ୍ୟବହାର କର"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ଇନ୍ପୁଟ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ଶ୍ରବଣ ଯନ୍ତ୍ର ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ପେୟାର୍"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ପେୟାର୍"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ଏବେର ଟଚ୍ ଡାଟା ଦେଖାଉଥିବା ସ୍କ୍ରୀନ୍ ଓଭର୍ଲେ"</string>
<string name="show_touches" msgid="8437666942161289025">"ଟାପ୍ ଦେଖାନ୍ତୁ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ଟାପ୍ ପାଇଁ ଭିଜୁଆଲ୍ ମତାମତ ଦେଖାନ୍ତୁ"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"ଦବାଯାଇଥିବା କୀ ଦେଖାନ୍ତୁ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ଦବାଯାଇଥିବା ଫିଜିକାଲ କୀ ପାଇଁ ଭିଜୁଆଲ ମତାମତ ଦେଖାନ୍ତୁ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"ସର୍ଫେସ୍ ଅପଡେଟ୍ ଦେଖାନ୍ତୁ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ସମଗ୍ର ୱିଣ୍ଡୋ ପୃଷ୍ଠ ଅପଡେଟ୍ ହେବା ବେଳେ ସେଗୁଡ଼ିକ ଫ୍ଲାସ୍ କରନ୍ତୁ"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"ଭ୍ୟୁ ଅପଡେଟ୍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c6ed2d5..3c4c4bc 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ਸਿਮ ਪਹੁੰਚ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ਆਡੀਓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ਆਡੀਓ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ਆਡੀਓ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ਮੀਡੀਆ ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ਫ਼ੋਨ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ਫ਼ੋਨ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ਇਨਪੁਟ ਲਈ ਵਰਤੋ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ਜੋੜਾਬੱਧ ਕਰੋ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ਸਕ੍ਰੀਨ ਓਵਰਲੇ ਮੌਜੂਦਾ ਸਪਰਸ਼ ਡਾਟਾ ਦਿਖਾ ਰਿਹਾ ਹੈ"</string>
<string name="show_touches" msgid="8437666942161289025">"ਟੈਪਾਂ ਦਿਖਾਓ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ਟੈਪਾਂ ਲਈ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਤੀਕਰਮ ਦਿਖਾਓ"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"ਕੁੰਜੀ ਦਬਾਉਣ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਦਿਖਾਓ"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"ਭੌਤਿਕ ਕੁੰਜੀ ਦਬਾਉਣ ਸੰਬੰਧੀ ਦ੍ਰਿਸ਼ਟੀਗਤ ਵਿਚਾਰ ਦਿਖਾਓ"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"ਸਰਫ਼ੇਸ ਅੱਪਡੇਟ ਦਿਖਾਓ"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"ਅੱਪਡੇਟ ਹੋਣ \'ਤੇ, ਸਮੁੱਚੀਆਂ ਵਿੰਡੋ ਸਰਫ਼ੇਸਾਂ ਫਲੈਸ਼ ਕਰੋ"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"\'ਅੱਪਡੇਟ ਦੇਖੋ\' ਨੂੰ ਦਿਖਾਓ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d9bdba7..62f7e81 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostęp do karty SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Dźwięk HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Dźwięk HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparaty słuchowe"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Połączono z aparatami słuchowymi"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Połączono z LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Połączono z funkcją audio multimediów"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Połączono z funkcją audio telefonu"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Użyj dla funkcji audio telefonu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Użyj do transferu plików"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Użyj do wprowadzania"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Używaj w przypadku aparatów słuchowych"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Używaj dla LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sparuj"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SPARUJ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Nakładka pokazująca dane o dotknięciach ekranu"</string>
<string name="show_touches" msgid="8437666942161289025">"Pokazuj dotknięcia"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Pokazuj potwierdzenie wizualne po dotknięciu"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Wyświetl naciśnięcia klawiszy"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Wyświetl opinie wizualne dla naciśnięć fizycznego klucza"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Pokazuj zmiany powierzchni"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Podświetlaj całe aktualizowane powierzchnie okien"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Pokazuj aktualizacje widoku"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index c75a371..6880511 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparelhos auditivos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectado a aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usado para transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Usar para aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Exibir dados de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostrar teclas pressionadas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostrar feedback visual de teclas pressionadas"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Piscar superfícies de toda a janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de exibição"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 1c90419..49e3f91 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparelhos auditivos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Ligado a aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ligado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ligado ao áudio de multimédia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ligado ao áudio do telefone"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do telefone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usar para transferência de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Usar para aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sincr."</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Apresentar dados atuais de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostrar toques em teclas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostrar feedback visual (toques em teclas físicas)"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Destacar a superfície da janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de vistas"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index c75a371..6880511 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparelhos auditivos"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectado a aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usado para transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Usar para aparelhos auditivos"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Exibir dados de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Mostrar teclas pressionadas"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Mostrar feedback visual de teclas pressionadas"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Piscar superfícies de toda a janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de exibição"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index cf6e0fe..1dce0e1 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acces la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparate auditive"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Conectat la aparatul auditiv"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectat la LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectat la profilul pentru conținut media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectat la componenta audio a telefonului"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Folosește pentru componenta audio a telefonului"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Folosește pentru transferul de fișiere"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Folosește pentru introducere date"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Folosește pentru aparatele auditive"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Folosește pentru LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Asociază"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"CONECTEAZĂ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Suprapunere care indică date curente pt. atingeri"</string>
<string name="show_touches" msgid="8437666942161289025">"Afișează atingerile"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afișează feedbackul vizual pentru atingeri"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Arată apăsările pe taste"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Arată feedback vizual pentru apăsările pe taste"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Actualizări suprafețe"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Iluminarea întregii fereastre la actualizare"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Afiș. actualizări ecran"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 35cf90b..79db17c 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Доступ к SIM-карте"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD Audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слуховые аппараты"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Слуховой аппарат подключен"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Подключено к LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Подключено к мультимедийному аудиоустройству"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Подключено к аудиоустройству телефона"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Использовать для аудиоустройства телефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Используется для передачи файлов"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Использовать для ввода"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Использовать для слухового аппарата"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Использовать для LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Добавить"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ДОБАВИТЬ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Показывать данные касаний и жестов"</string>
<string name="show_touches" msgid="8437666942161289025">"Показывать нажатия"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Визуальный отклик при нажатии"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Показывать нажатия клавиш"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Показывать визуальный отклик при нажатии клавиш"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Показ. обнов. поверхности"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Подсвечивать поверхности окон при обновлении"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Показывать обнов. экрана"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 517e8f5..c43f5dd 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM ප්රවේශය"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ශ්රව්යය: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ශ්රව්යය"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"ශ්රවණාධාරක"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ශ්රව්ය"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"ශ්රවණාධාරක වෙත සම්බන්ධ කළා"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ශ්රව්ය වෙත සම්බන්ධ විය"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"මාධ්ය ශ්රව්යට සම්බන්ධ විය"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"දුරකතනයේ ශ්රව්යට සම්බන්ධ විය"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"දුරකථන ශ්රව්ය සඳහා භාවිතා කෙරේ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ගොනු හුවමාරුව සඳහා භාවිතා කරන්න"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ආදානය සඳහා භාවිතා කරන්න"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ශ්රවණාධාර සඳහා භාවිත කරන්න"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO සඳහා භාවිත කරන්න"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"යුගල කරන්න"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"යුගල කරන්න"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"තිර උඩැතිරිය වර්තමාන ස්පර්ශ දත්ත පෙන්වයි"</string>
<string name="show_touches" msgid="8437666942161289025">"තට්ටු කිරීම් පෙන්වන්න"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"තට්ටු කිරීම් සඳහා දෘශ්ය ප්රතිපෝෂණ පෙන්වන්න"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"යතුරු එබීම් පෙන්වන්න"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"භෞතික යතුරු එබීම සඳහා දෘශ්ය ප්රතිපෝෂණය පෙන්වන්න"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"පෘෂ්ඨ යාවත්කාලීන පෙන්වන්න"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"යාවත්කාලින වනවිට මුළු කවුළු තලයම දැල්වෙන්න"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"නැරඹීම් යාවත්කාලීන පෙන්වන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5d1107e..ec383f9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Prístup k SIM karte"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Načúvadlá"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Pripojené k načúvadlám"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Pripojené k systému LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Pripojené ku zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Pripojené ku zvuku telefónu"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Použiť pre zvuk telefónu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Použiť na prenos súborov"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Použiť pre vstup"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Používať pre načúvadlá"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Používať s profilom LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Párovať"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PÁROVAŤ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Zobraziť prekryvnú vrstvu s aktuálnymi údajmi o klepnutiach"</string>
<string name="show_touches" msgid="8437666942161289025">"Zobrazovať klepnutia"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vizuálne znázorňovať klepnutia"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Zobrazovať stlač. kláves."</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Zobr. vizuálnu spätnú väzbu fyz. stlač. klávesov"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Ukazovať obnovenia obsahu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Rozblikať obsah okna pri aktualizácii"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ukazovať obnovenia zobrazenia"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index e1c9c73..4d0e7a8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostop do kartice SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Zvok visoke kakovosti"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Slušni aparati"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE zvok"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Povezava s slušnimi aparati je vzpostavljena."</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezan s profilom za predstavnostni zvok"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezava s profilom za zvok telefona vzpostavljena"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Uporabi za zvok telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Uporabi za prenos datotek"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Uporabi za vnos"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Uporabi za slušne aparate"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Uporaba za profil LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Seznani"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SEZNANI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Prekrivanje zaslona prikazuje trenutni dotik."</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dotike"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikaži vizualne povratne informacije za dotike."</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Pokaži pritiske tipk"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Pokaži vizualne povratne informacije za pritiske fizičnih tipk"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Pokaži posodob. površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ob posodobitvi osveži celotne površine oken."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži posodob. pogleda"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 373e055..2fdac37 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Qasje në kartën SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Aparatet e dëgjimit"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Lidhur me aparatet e dëgjimit"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"U lidh me audion LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"U lidh me audion e medias"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"U lidh me audion e telefonit"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Përdor për audion e telefonit"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Përdor për transferimin e skedarëve"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Përdore për hyrjen"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Përdore për aparatet e dëgjimit"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Përdor për LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Çifto"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ÇIFTO"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Mbivendosja e ekranit tregon të dhënat e prekjes"</string>
<string name="show_touches" msgid="8437666942161289025">"Shfaq trokitjet"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Shfaq reagimet vizuale për trokitjet"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Shfaq shtypjet e tasteve"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Shfaq reagime vizuale për shtypjen e tasteve fizike"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Shfaq përditësimet e sipërfaqes"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ndriço të gjitha sipërfaqet e dritares kur ato të përditësohen"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Shfaq përditësimet e pamjes"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b81f18e..dc698ce 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Приступ SIM картици"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD звук: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD звук"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слушни апарати"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Повезано са слушним апаратима"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Повезано са LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Повезано са звуком медија"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Повезано са звуком телефона"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Коришћење за аудио телефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Коришћење за пренос датотека"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Користи за улаз"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Користи за слушне апарате"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Користите за LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Упари"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"УПАРИ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Преклопни елемент са тренутним подацима о додиру"</string>
<string name="show_touches" msgid="8437666942161289025">"Приказуј додире"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Приказује визуелне повратне информације за додире"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Приказуј притиске тастера"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Приказује повратне информације за притиске тастера"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Прикажи ажурирања површине"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Осветљава све површине прозора када се ажурирају"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Прикажи ажурирања приказа"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2915d39..64412dd5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-åtkomst"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ljud: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ljud"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hörapparater"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Ansluten till hörapparater"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ansluten till LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ansluten till medialjud"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ansluten till telefonens ljud"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Använd för telefonens ljud"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Använd för filöverföring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Använd för inmatning"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Använd med hörapparater"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Använd för LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parkoppla"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PARKOPPLA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Överlägg på skärmen med aktuella skärmtryck"</string>
<string name="show_touches" msgid="8437666942161289025">"Visa tryck"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Visa visuell feedback för tryck"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Visa tangenttryckningar"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Visa visuell feedback för tangenttryckningar"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Visa ytuppdateringar"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Hela fönstret blinkar vid uppdatering"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Visa visningsuppdatering"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 0ec1278..4893fe83 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Ufikiaji wa SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Sauti ya HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Sauti ya HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Visaidizi vya kusikia"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Imeunganishwa kwenye visaidizi vya kusikia"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Imeunganishwa kwenye LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Imeunganishwa kwenye sikika ya njia ya mawasiliano"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Imeunganishwa kwenye sauti ya simu"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Tumia kwa sauti ya simu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Tumia kwa hali faili"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Tumia kwa kuingiza"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Tumia kwa visaidizi vya kusikia"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Tumia kwa ajili ya LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Oanisha"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"OANISHA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Kuegeshwa kwa skrini ikionyesha data ya mguso ya sasa"</string>
<string name="show_touches" msgid="8437666942161289025">"Onyesha unapogusa"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Onyesha ishara za kuthibitisha unapogusa"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Onyesha mibofyo ya vitufe"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Onyesha muhtasari wa mibofyo halisi ya vitufe"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Onyesha masasisho ya sehemu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Angaza dirisha lote zitakaposasisha"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Onyesha taarifa za kuonekana"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7e2d74e..b72c533 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"சிம் அணுகல்"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ஆடியோ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ஆடியோ"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"செவித்துணைக் கருவிகள்"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ஆடியோ"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"செவித்துணைக் கருவிகளுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ஆடியோவுடன் இணைக்கப்பட்டுள்ளது"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ஃபைல் பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"உள்ளீட்டுக்குப் பயன்படுத்து"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"செவித்துணைக் கருவிகளுக்காகப் பயன்படுத்தப்படும்"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIOவிற்குப் பயன்படுத்தும்"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"இணை"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"இணை"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"திரையின் மேல் அடுக்கானது தற்போது தொடப்பட்டிருக்கும் தரவைக் காண்பிக்கிறது"</string>
<string name="show_touches" msgid="8437666942161289025">"தட்டல்களைக் காட்டு"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"தட்டல்களின் போது காட்சி அறிகுறிகளைக் காட்டும்"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"பட்டன் அழுத்தத்தை காட்டவா"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"பட்டன் அழுத்தங்களைக் காட்சி மூலம் உறுதிப்படுத்தும்"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"மேலோட்ட புதுப்பிப்புகளைக் காட்டு"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"சாளரத்தின் பரப்புநிலைகள் புதுப்பிக்கப்படும்போது, அவற்றை முழுவதுமாகக் காட்டும்"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"வியூ அப்டேட்ஸைக் காட்டு"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 6d2449c..32738bb 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ప్రస్తుత టచ్ డేటాను చూపుతోన్న స్క్రీన్"</string>
<string name="show_touches" msgid="8437666942161289025">"నొక్కినవి చూపు"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"నొక్కినప్పుడు దృశ్యపరమైన ప్రతిస్పందన చూపు"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"కీ ప్రెస్లను చూడండి"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"భౌతిక కీ ప్రెస్ల విజువల్ ఫీడ్బ్యాక్ను చూడండి"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"సర్ఫేస్ అప్డేట్లను చూపు"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"విండో సర్ఫేస్లన్నీ అప్డేట్ అయితే ఫ్లాష్ చేయి"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"వీక్షణ అప్డేట్లను చూపు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 1e1cbfc..14ef3a3 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"การเข้าถึงซิม"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"เสียง HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"เสียง HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"เครื่องช่วยฟัง"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"เชื่อมต่อกับเครื่องช่วยฟังแล้ว"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"เชื่อมต่อกับ LE Audio แล้ว"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"เชื่อมต่อกับระบบเสียงของสื่อแล้ว"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"เชื่อมต่อกับระบบเสียงของโทรศัพท์แล้ว"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ใช้สำหรับระบบเสียงของโทรศัพท์"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ใช้สำหรับการโอนไฟล์"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ใช้สำหรับการป้อนข้อมูล"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"ใช้สำหรับเครื่องช่วยฟัง"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"ใช้สำหรับ LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"จับคู่"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"จับคู่อุปกรณ์"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"การวางซ้อนหน้าจอที่แสดงข้อมูลการแตะในปัจจุบัน"</string>
<string name="show_touches" msgid="8437666942161289025">"แสดงการแตะ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"แสดงผลตอบสนองแบบภาพเมื่อแตะ"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"แสดงการกดแป้น"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"แสดงฟีดแบ็กที่เป็นภาพสำหรับการกดแป้นพิมพ์"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"แสดงการอัปเดตพื้นผิว"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"กะพริบหน้าต่างทั้งหมดเมื่อมีการอัปเดต"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"แสดงการอัปเดตมุมมอง"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index f0cb867..ab4acb6 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Access sa SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Mga hearing aid"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Nakakonekta sa mga hearing aid"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Nakakonekta sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Konektado sa media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Nakakonekta sa audio ng telepono"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Ginagamit para sa audio ng telepono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Ginagamit para sa paglilipat ng file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gamitin para sa input"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Gamitin para sa mga hearing aid"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gamitin para sa LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Ipares"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"IPARES"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay ng screen na nagpapakita ng touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Ipakita ang mga pag-tap"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ipakita ang visual na feedback para sa mga pag-tap"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Ipakita ang mga key press"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Ipakita: visual feedback ng mga physical key press"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Ipakita update sa surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"I-flash ang buong window surface kapag nag-update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ipakita update ng view"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6b7e699..abbef53 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM Erişimi"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ses: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ses"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"İşitme cihazları"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"İşitme cihazlarına bağlandı"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio\'ya bağlandı"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Medya sesine bağlanıldı"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon sesine bağlandı"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Telefon sesi için kullan"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Dosya aktarımı için kullan"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Giriş için kullan"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"İşitme cihazları için kullan"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO kullan"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Eşle"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"EŞLE"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Mevcut dokunmatik verilerini gösteren yer paylaşımı"</string>
<string name="show_touches" msgid="8437666942161289025">"Dokunmayı göster"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Dokunmalarda görsel geri bildirim göster"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Basılan tuşları göster"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Fiziksel tuşlara basınca görsel geri bildirim ver"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Yüzey güncellemelerini göster"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Güncellenirken tüm pencere yüzeylerini yakıp söndür"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Görünüm güncellemelerini göster"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a5296ed..bf297e6 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Доступ до SIM-карти"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-аудіо: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-аудіо"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Слухові апарати"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Підключено до слухових апаратів"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Підключено до LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Підключено до аудіоджерела"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Підключено до звуку телеф."</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Викор. для звуку тел."</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Викор. для перед. файлів"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Викор. для введ."</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Використовувати для слухових апаратів"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Використовувати для LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Підключити"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ПІДКЛЮЧИТИСЯ"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Показувати на екрані жести й натискання"</string>
<string name="show_touches" msgid="8437666942161289025">"Показувати дотики"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Показувати візуальну реакцію на торкання"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Показувати натиск. клавіш"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Показувати візуальний відгук на натискання клавіш"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Показ. оновлення поверхні"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Підсвічувати вікна повністю під час оновлення"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Показувати оновлення областей"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 944726a..db2bb26 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM رسائی"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD آڈیو: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD آڈیو"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"سماعتی آلات"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE آڈیو"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"سماعتی آلات سے منسلک ہے"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE آڈیو سے منسلک ہے"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"میڈیا آڈیو سے مربوط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"فون آڈیو سے مربوط"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"فون آڈیو کیلئے استعمال کریں"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"فائل منتقل کرنے کیلئے استعمال کریں"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ان پٹ کیلئے استعمال"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"سماعتی آلات کیلئے استعمال کریں"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO کے لیے استعمال کریں"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"جوڑا بنائیں"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"جوڑا بنائیں"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"موجودہ ٹچ ڈیٹا دکھانے والا اسکرین اوور لے"</string>
<string name="show_touches" msgid="8437666942161289025">"تھپتھپاہٹیں دکھائیں"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"تھپتھپاہٹوں کیلئے بصری تاثرات دکھائیں"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"\'کلید کو دبانا\' دکھائیں"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"\'طبعی کلید کو دبانا\' کیلئے ویژوئل تاثرات دکھائیں"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"سطح کے اپ ڈیٹس دکھائیں"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"اپ ڈیٹ ہونے پر ونڈو کی پوری سطحیں جھلملائیں"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"منظر کے اپ ڈیٹس دکھائیں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 86653a2..96e5d6a 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -355,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekranda bosilgan va tegilgan joylarni vizuallashtirish"</string>
<string name="show_touches" msgid="8437666942161289025">"Bosishlarni ko‘rsatish"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ekranda bosilgan joylardagi nuqtalarni ko‘rsatish"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Tugma bosishlarini chiqarish"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Jismoniy tugmani bosishlar uchun vizual fikr-mulohazani chiqarish"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Yuza yangilanishlarini ko‘rsatish"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Yangilangandan so‘ng to‘liq oyna sirtlarini miltillatish"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Yangilash oynasini ochish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 712b5ae..7035077 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Truy cập SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Âm thanh HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Âm thanh HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Thiết bị trợ thính"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Âm thanh năng lượng thấp"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Đã kết nối với thiết bị trợ thính"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Đã kết nối với âm thanh LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Đã kết nối với âm thanh nội dung nghe nhìn"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Đã kết nối với âm thanh điện thoại"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Sử dụng cho âm thanh điện thoại"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Sử dụng để chuyển tệp"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Sử dụng để nhập"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Dùng cho thiết bị trợ thính"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Dùng cho LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Ghép nối"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"GHÉP NỐI"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Lớp phủ màn hình hiển thị dữ liệu chạm hiện tại"</string>
<string name="show_touches" msgid="8437666942161289025">"Hiện số lần nhấn"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Hiển thị phản hồi trực quan cho các lần nhấn"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Hiện thao tác nhấn phím"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Hiện phản hồi trực quan cho thao tác nhấn phím vật lý"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Hiện bản cập nhật giao diện"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Chuyển nhanh toàn bộ các giao diện cửa sổ khi các giao diện này cập nhật"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Hiện bản cập nhật chế độ xem"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index d20b421..fabc004 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM 卡访问权限"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 音频:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 音频"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"助听器"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE 音频"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"已连接到助听器"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已连接到 LE 音频"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已连接到媒体音频"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已连接到手机音频"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用于手机音频"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用于文件传输"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用于输入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"用于助听器"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"用于 LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"配对"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"配对"</string>
@@ -296,11 +293,11 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"蓝牙音频 LDAC 编解码器:播放质量"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"触发蓝牙音频 LDAC\n编解码器选择:播放质量"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"正在流式传输:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"私人 DNS"</string>
+ <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"专用 DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"选择私人 DNS 模式"</string>
<string name="private_dns_mode_off" msgid="7065962499349997041">"已关闭"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"自动"</string>
- <string name="private_dns_mode_provider" msgid="3619040641762557028">"私人 DNS 提供商主机名"</string>
+ <string name="private_dns_mode_provider" msgid="3619040641762557028">"专用 DNS 提供商主机名"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"输入 DNS 提供商的主机名"</string>
<string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"无法连接"</string>
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"屏幕叠加层显示当前触摸数据"</string>
<string name="show_touches" msgid="8437666942161289025">"显示点按操作反馈"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"显示点按操作的视觉反馈"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"显示按键操作"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"显示实体按键操作的视觉反馈"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"显示面 (surface) 更新"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"窗口中的面 (surface) 更新时全部闪烁"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"显示视图更新"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f83e9c6..9ec57a3 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM 卡存取"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"高清音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"高清音訊"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"助聽器"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"已連接助聽器"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連接 LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已連接媒體音頻裝置"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已連接手機耳機"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用於手機音效"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用於輸入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"用於助聽器"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"用於 LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"配對"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"配對"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"在螢幕上重疊顯示目前的觸控資料"</string>
<string name="show_touches" msgid="8437666942161289025">"顯示輕按回應"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"顯示輕按位置的視覺回應"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"顯示按鍵操作"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"顯示實際按鍵操作的視覺回應"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"顯示表層更新"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"更新表層時閃動整個視窗表層"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"顯示畫面更新"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 2aae4a8..59e66aa 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM 卡存取權"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 高解析音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 高解析音訊"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"助聽器"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"已連上助聽器"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連上 LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"連接至媒體音訊"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"連接至電話音訊"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用於電話音訊"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用於輸入"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"用於助聽器"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"用於 LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"配對"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"配對"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"在螢幕圖層上顯示目前的觸控資料"</string>
<string name="show_touches" msgid="8437666942161289025">"顯示觸控回應"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"顯示觸控位置的視覺回應"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"顯示按鍵操作"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"顯示實際按鍵操作的視覺回饋"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"顯示表層更新"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"更新表層時閃爍顯示整個視窗表層"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"顯示畫面更新"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6a56006..d292bd5 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -114,11 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Ukufinyelela kwe-SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Umsindo we-HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Umsindo we-HD"</string>
- <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
- <skip />
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Imishini yendlebe"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Umsindo we-LE"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Kuxhume emishinini yendlebe"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Kuxhunywe kumsindo we-LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ixhume emsindweni wemidiya"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ixhunywe kumsindo wefoni"</string>
@@ -136,8 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Sebenziselwa umsindo wefoni"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Sebenziselwa ukudlulisa ifayela"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Isetshenziselwa okufakwayo"</string>
- <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
- <skip />
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Sebenzisa imishini yendlebe"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Sebenzisela i-LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Bhangqa"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BHANGQA"</string>
@@ -358,10 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Imbondela yesikrini ibonisa idatha yokuthinta yamanje"</string>
<string name="show_touches" msgid="8437666942161289025">"Bonisa amathebhu"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Bonisa izmpendulo ebukekayo ngamathebhu"</string>
- <!-- no translation found for show_key_presses (6360141722735900214) -->
- <skip />
- <!-- no translation found for show_key_presses_summary (725387457373015024) -->
- <skip />
+ <string name="show_key_presses" msgid="6360141722735900214">"Bonisa ukucindezela ukhiye"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Bonisa impendulo ebonakalayo yokucindezela ukhiye obonakalayo"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Buka izibuyekezo ezibonakalayo"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Khanyisa ukubonakala kwalo lonke iwindi uma libuyekezwa"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Bonisa izibuyekezo zokubuka"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 3e2b800..3adb882 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -643,8 +643,10 @@
array must also be populated with a content description for each image. -->
<array name="avatar_images"/>
- <!-- Content descriptions for each of the images in the avatar_images array. -->
- <string-array name="avatar_image_descriptions"/>
+ <!-- Content descriptions for each of the images in the avatar_images array. When overlaid
+ these values should be translated, but this empty array must not be translated or it may
+ replace the real descriptions with an empty array. -->
+ <string-array name="avatar_image_descriptions" translatable="false"/>
<!-- NOTE: if you change this, you must also add the corresponding scale key and lookup table to
frameworks/base/core/java/android/content/res/FontScaleConverterFactory.java -->
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 91549d7..07854bd 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -124,4 +124,5 @@
<dimen name="dialog_bottom_padding">18dp</dimen>
<dimen name="dialog_side_padding">24dp</dimen>
<dimen name="dialog_button_bar_top_padding">32dp</dimen>
+ <dimen name="button_corner_radius">28dp</dimen>
</resources>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 4ac4aae..1249c6b 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -93,7 +93,6 @@
</style>
<style name="DialogButtonPositive">
- <item name="android:buttonCornerRadius">0dp</item>
<item name="android:background">@drawable/dialog_btn_filled</item>
<item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
<item name="android:textSize">14sp</item>
@@ -104,7 +103,6 @@
</style>
<style name="DialogButtonNegative">
- <item name="android:buttonCornerRadius">28dp</item>
<item name="android:background">@drawable/dialog_btn_outline</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">14sp</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 79fb566..a05a6e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -237,7 +237,8 @@
"startBroadcast: language = " + language + " ,programInfo = " + programInfo);
}
buildContentMetadata(language, programInfo);
- mService.startBroadcast(mBluetoothLeAudioContentMetadata, mBroadcastCode);
+ mService.startBroadcast(mBluetoothLeAudioContentMetadata,
+ (mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
}
public String getProgramInfo() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
index c88ed8e..9f15c1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
@@ -2,7 +2,6 @@
andychou@google.com
arcwang@google.com
changbetty@google.com
-goldmanj@google.com
qal@google.com
wengsu@google.com
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index 9567a3b..ea65ade 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.settingslib.core;
import android.app.admin.DevicePolicyManager;
@@ -6,8 +22,11 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.EmptySuper;
+import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.os.BuildCompat;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
@@ -52,6 +71,13 @@
}
/**
+ * Called on view created.
+ */
+ @EmptySuper
+ public void onViewCreated(@NonNull LifecycleOwner viewLifecycleOwner) {
+ }
+
+ /**
* Updates the current status of preference (summary, switch state, etc)
*/
public void updateState(Preference preference) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS
index 61c73fb..372eb81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/OWNERS
@@ -1,7 +1,6 @@
# Default reviewers for this and subdirectories.
bonianchen@google.com
changbetty@google.com
-goldmanj@google.com
wengsu@google.com
zoeychen@google.com
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index bcbd1ca..848b177 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -243,7 +243,7 @@
int index = indexFromPosition(position);
viewHolder.setSelected(position == mSelectedPosition);
viewHolder.setDrawable(mImageDrawables.get(index));
- if (mImageDescriptions != null) {
+ if (mImageDescriptions != null && index < mImageDescriptions.size()) {
viewHolder.setContentDescription(mImageDescriptions.get(index));
} else {
viewHolder.setContentDescription(getString(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index fd986e5..21eb35a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -87,7 +87,13 @@
// Fallback for platforms that do not need friction icon resources.
frictionSld = null;
}
- return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
+ if (frictionSld != null) {
+ StateListDrawable val = (StateListDrawable) frictionSld.getDrawable(0);
+ frictionSld.recycle();
+ return val;
+ } else {
+ return null;
+ }
}
// Used for fake pref.
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
index f3b600c..b9449ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -3,7 +3,6 @@
arcwang@google.com
asapperstein@google.com
changbetty@google.com
-goldmanj@google.com
qal@google.com
wengsu@google.com
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 4234fbd..e31a672 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -176,10 +176,21 @@
VALIDATORS.put(Global.REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.AWARE_ALLOWED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.POWER_BUTTON_SHORT_PRESS, new InclusiveIntegerRangeValidator(0, 7));
+ VALIDATORS.put(Global.POWER_BUTTON_DOUBLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
+ VALIDATORS.put(Global.POWER_BUTTON_TRIPLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 5));
VALIDATORS.put(
Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Global.KEY_CHORD_POWER_VOLUME_UP, new InclusiveIntegerRangeValidator(0, 2));
+ VALIDATORS.put(
+ Global.STEM_PRIMARY_BUTTON_SHORT_PRESS, new InclusiveIntegerRangeValidator(0, 1));
+ VALIDATORS.put(
+ Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS, new InclusiveIntegerRangeValidator(0, 1));
+ VALIDATORS.put(
+ Global.STEM_PRIMARY_BUTTON_TRIPLE_PRESS, new InclusiveIntegerRangeValidator(0, 1));
+ VALIDATORS.put(
+ Global.STEM_PRIMARY_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3a38b69..a2895a4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5118,14 +5118,15 @@
Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY);
final boolean supportMagnificationArea = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_magnification_area);
- final int capability = supportMagnificationArea
- ? R.integer.def_accessibility_magnification_capabilities
- : Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
final String supportShowPrompt = supportMagnificationArea ? "1" : "0";
if (magnificationCapabilities.isNull()) {
+ final int capability = supportMagnificationArea
+ ? getContext().getResources().getInteger(
+ R.integer.def_accessibility_magnification_capabilities)
+ : Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
secureSettings.insertSettingLocked(
Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
- String.valueOf(getContext().getResources().getInteger(capability)),
+ String.valueOf(capability),
null, true, SettingsState.SYSTEM_PACKAGE_NAME);
if (isMagnificationSettingsOn(secureSettings)) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index e3153e0..73ead3c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -94,6 +94,7 @@
static final int SETTINGS_VERSION_NEW_ENCODING = 121;
+ public static final int MAX_LENGTH_PER_STRING = 32768;
private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
@@ -430,6 +431,19 @@
return false;
}
+ final boolean isNameTooLong = name.length() > SettingsState.MAX_LENGTH_PER_STRING;
+ final boolean isValueTooLong =
+ value != null && value.length() > SettingsState.MAX_LENGTH_PER_STRING;
+ if (isNameTooLong || isValueTooLong) {
+ // only print the first few bytes of the name in case it is long
+ final String errorMessage = "The " + (isNameTooLong ? "name" : "value")
+ + " of your setting ["
+ + (name.length() > 20 ? (name.substring(0, 20) + "...") : name)
+ + "] is too long. The max length allowed for the string is "
+ + MAX_LENGTH_PER_STRING + ".";
+ throw new IllegalArgumentException(errorMessage);
+ }
+
Setting oldState = mSettings.get(name);
String oldValue = (oldState != null) ? oldState.value : null;
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
@@ -860,7 +874,6 @@
final int settingCount = settings.size();
for (int i = 0; i < settingCount; i++) {
-
Setting setting = settings.valueAt(i);
if (setting.isTransient()) {
if (DEBUG_PERSISTENCE) {
@@ -869,14 +882,21 @@
continue;
}
- if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
- setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
- setting.getTag(), setting.isDefaultFromSystem(),
- setting.isValuePreservedInRestore())) {
- if (DEBUG_PERSISTENCE) {
- Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
- + setting.getValue());
+ try {
+ if (writeSingleSetting(mVersion, serializer, setting.getId(),
+ setting.getName(),
+ setting.getValue(), setting.getDefaultValue(),
+ setting.getPackageName(),
+ setting.getTag(), setting.isDefaultFromSystem(),
+ setting.isValuePreservedInRestore())) {
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
+ + setting.getValue());
+ }
}
+ } catch (IOException ex) {
+ Slog.e(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName()
+ + " due to error writing to disk", ex);
}
}
serializer.endTag(null, TAG_SETTINGS);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index a64cf11..140b1e0 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -596,7 +596,14 @@
Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD,
Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT,
Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT,
+ Settings.Global.POWER_BUTTON_SHORT_PRESS,
+ Settings.Global.POWER_BUTTON_DOUBLE_PRESS,
+ Settings.Global.POWER_BUTTON_TRIPLE_PRESS,
Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
+ Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS,
+ Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS,
+ Settings.Global.STEM_PRIMARY_BUTTON_TRIPLE_PRESS,
+ Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS,
Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, // Temporary for R beta
Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
Settings.Global.CACHED_APPS_FREEZER_ENABLED,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 55160fb..26cac37 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -31,21 +31,21 @@
public class SettingsStateTest extends AndroidTestCase {
public static final String CRAZY_STRING =
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" +
- "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
- "\u001b\u001c\u001d\u001e\u001f\u0020" +
- "fake_setting_value_1" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
- "\ud800\udc00\udbff\udfff" + // surrogate pairs
- "\uD800ab\uDC00 " + // broken surrogate pairs
- "日本語";
+ "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
+ "\u001b\u001c\u001d\u001e\u001f\u0020" +
+ "fake_setting_value_1" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
+ "\ud800\udc00\udbff\udfff" + // surrogate pairs
+ "\uD800ab\uDC00 " + // broken surrogate pairs
+ "日本語";
private static final String TEST_PACKAGE = "package";
private static final String SYSTEM_PACKAGE = "android";
@@ -170,11 +170,11 @@
final PrintStream os = new PrintStream(new FileOutputStream(file));
os.print(
"<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" +
- "<settings version=\"120\">" +
- " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
- " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
- " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
- "</settings>");
+ "<settings version=\"120\">" +
+ " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
+ " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
+ " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
+ "</settings>");
os.close();
final SettingsState ss = new SettingsState(getContext(), lock, file, 1,
@@ -408,4 +408,50 @@
}
assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
}
+
+ public void testLargeSettingKey() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+ final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+ final String testValue = "testValue";
+ synchronized (mLock) {
+ // Test system package
+ try {
+ settingsState.insertSettingLocked(largeKey, testValue, null, true, SYSTEM_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ // Test non system package
+ try {
+ settingsState.insertSettingLocked(largeKey, testValue, null, true, TEST_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ }
+ }
+
+ public void testLargeSettingValue() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+ final String testKey = "testKey";
+ final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+ synchronized (mLock) {
+ // Test system package
+ try {
+ settingsState.insertSettingLocked(testKey, largeValue, null, true, SYSTEM_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ // Test non system package
+ try {
+ settingsState.insertSettingLocked(testKey, largeValue, null, true, TEST_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ }
+ }
}
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
index baaddf5..8a5b7da 100644
--- a/packages/Shell/src/com/android/shell/Screenshooter.java
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -21,12 +21,10 @@
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.view.WindowManagerGlobal;
import android.window.ScreenCapture;
-import android.window.ScreenCapture.ScreenCaptureListener;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
-import android.window.ScreenCapture.ScreenshotSync;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
/**
* Helper class used to take screenshots.
@@ -46,15 +44,15 @@
static Bitmap takeScreenshot() {
Log.d(TAG, "Taking fullscreen screenshot");
// Take the screenshot
- final Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture =
+ final SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
try {
WindowManagerGlobal.getWindowManagerService().captureDisplay(DEFAULT_DISPLAY, null,
- syncScreenCapture.first);
+ syncScreenCapture);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
- final ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.second.get();
+ final ScreenshotHardwareBuffer screenshotBuffer = syncScreenCapture.getBuffer();
final Bitmap screenShot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
if (screenShot == null) {
Log.e(TAG, "Failed to take fullscreen screenshot");
diff --git a/packages/SoundPicker/res/values-kn/strings.xml b/packages/SoundPicker/res/values-kn/strings.xml
index e6a05c2..da90ccb 100644
--- a/packages/SoundPicker/res/values-kn/strings.xml
+++ b/packages/SoundPicker/res/values-kn/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="ringtone_default" msgid="798836092118824500">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್ಟೋನ್"</string>
- <string name="notification_sound_default" msgid="8133121186242636840">"ಡೀಫಾಲ್ಟ್ ಅಧಿಸೂಚನೆ ಧ್ವನಿ"</string>
+ <string name="notification_sound_default" msgid="8133121186242636840">"ಡೀಫಾಲ್ಟ್ ನೋಟಿಫಿಕೇಶನ್ ಧ್ವನಿ"</string>
<string name="alarm_sound_default" msgid="4787646764557462649">"ಡೀಫಾಲ್ಟ್ ಅಲಾರಾಂ ಧ್ವನಿ"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"ರಿಂಗ್ಟೋನ್ ಸೇರಿಸಿ"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"ಅಲಾರಾಂ ಸೇರಿಸಿ"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2c0d73a..2913c16 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -363,7 +363,7 @@
android:killAfterRestore="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
- android:icon="@drawable/icon"
+ android:icon="@drawable/android14_patch_adaptive"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/Theme.SystemUI"
@@ -1068,15 +1068,6 @@
android:exported="true">
</provider>
- <!-- Provides list and realistic previews of clock faces for the picker app. -->
- <provider
- android:name="com.android.keyguard.clock.ClockOptionsProvider"
- android:authorities="com.android.keyguard.clock"
- android:enabled="false"
- android:exported="false"
- android:grantUriPermissions="true">
- </provider>
-
<receiver
android:name=".statusbar.KeyboardShortcutsReceiver"
android:exported="true">
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 01e6bf0..7a5a382 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -66,7 +66,7 @@
},
{
// Permission indicators
- "name": "CtsPermission3TestCases",
+ "name": "CtsPermissionUiTestCases",
"options": [
{
"exclude-annotation": "org.junit.Ignore"
@@ -75,7 +75,7 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
- "include-filter": "android.permission3.cts.CameraMicIndicatorsPermissionTest"
+ "include-filter": "android.permissionui.cts.CameraMicIndicatorsPermissionTest"
}
]
},
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml
index b97df64..877a43c 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-es/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú de accesibilidad"</string>
+ <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menú Accesibilidad"</string>
<string name="accessibility_menu_intro" msgid="3164193281544042394">"El menú de accesibilidad es un menú de gran tamaño que se muestra en pantalla para controlar tu dispositivo. Puedes bloquear el dispositivo, controlar el volumen y el brillo, hacer capturas de pantalla y más."</string>
<string name="assistant_label" msgid="6796392082252272356">"Asistente"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Asistente"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
index 6ae65cb..c64ec6f 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
+import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.TouchDelegate;
@@ -47,10 +48,11 @@
private final ShortcutDrawableUtils mShortcutDrawableUtils;
public A11yMenuAdapter(
- AccessibilityMenuService service, List<A11yMenuShortcut> shortcutDataList) {
+ AccessibilityMenuService service,
+ Context displayContext, List<A11yMenuShortcut> shortcutDataList) {
this.mService = service;
this.mShortcutDataList = shortcutDataList;
- mInflater = LayoutInflater.from(service);
+ mInflater = LayoutInflater.from(displayContext);
mShortcutDrawableUtils = new ShortcutDrawableUtils(service);
@@ -75,7 +77,9 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- convertView = mInflater.inflate(R.layout.grid_item, null);
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.grid_item, parent, false);
+ }
A11yMenuShortcut shortcutItem = (A11yMenuShortcut) getItem(position);
// Sets shortcut icon and label resource.
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index 5b7bbe8..edd6a48 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -17,11 +17,13 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static java.lang.Math.max;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -135,15 +137,13 @@
initLayoutParams();
}
- final Display display = mService.getSystemService(
- DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
-
- mLayout = new FrameLayout(
- mService.createDisplayContext(display).createWindowContext(
- WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, null));
+ final Display display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ final Context context = mService.createDisplayContext(display).createWindowContext(
+ TYPE_ACCESSIBILITY_OVERLAY, null);
+ mLayout = new FrameLayout(context);
updateLayoutPosition();
- inflateLayoutAndSetOnTouchListener(mLayout);
- mA11yMenuViewPager = new A11yMenuViewPager(mService);
+ inflateLayoutAndSetOnTouchListener(mLayout, context);
+ mA11yMenuViewPager = new A11yMenuViewPager(mService, context);
mA11yMenuViewPager.configureViewPagerAndFooter(mLayout, createShortcutList(), pageIndex);
mWindowManager.addView(mLayout, mLayoutParameter);
mLayout.setVisibility(lastVisibilityState);
@@ -169,8 +169,8 @@
mLayoutParameter.setTitle(mService.getString(R.string.accessibility_menu_service_name));
}
- private void inflateLayoutAndSetOnTouchListener(ViewGroup view) {
- LayoutInflater inflater = LayoutInflater.from(mService);
+ private void inflateLayoutAndSetOnTouchListener(ViewGroup view, Context displayContext) {
+ LayoutInflater inflater = LayoutInflater.from(displayContext);
inflater.inflate(R.layout.paged_menu, view);
view.setOnTouchListener(mService);
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
index 0a349e5..b969017 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
@@ -147,8 +147,12 @@
/** The container layout for a11y menu. */
private ViewGroup mA11yMenuLayout;
- public A11yMenuViewPager(AccessibilityMenuService service) {
+ /** Display context for inflating views. */
+ private Context mDisplayContext;
+
+ public A11yMenuViewPager(AccessibilityMenuService service, Context displayContext) {
this.mService = service;
+ this.mDisplayContext = displayContext;
}
/**
@@ -213,10 +217,11 @@
}
private void addGridPage(List<A11yMenuShortcut> shortcutDataListInPage) {
- LayoutInflater inflater = LayoutInflater.from(mService);
+ LayoutInflater inflater = LayoutInflater.from(mDisplayContext);
View view = inflater.inflate(R.layout.grid_view, null);
GridView gridView = view.findViewById(R.id.gridview);
- A11yMenuAdapter adapter = new A11yMenuAdapter(mService, shortcutDataListInPage);
+ A11yMenuAdapter adapter = new A11yMenuAdapter(
+ mService, mDisplayContext, shortcutDataListInPage);
gridView.setNumColumns(GridViewParams.getGridColumnCount(mService));
gridView.setAdapter(adapter);
mGridPageList.add(gridView);
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 23e3a01..1a03ede 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -34,7 +34,6 @@
import android.view.ViewGroupOverlay
import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
-import java.lang.IllegalArgumentException
import java.util.LinkedList
import kotlin.math.min
import kotlin.math.roundToInt
@@ -240,7 +239,7 @@
val ghostView = this.ghostView ?: return
val backgroundView = this.backgroundView!!
- if (!state.visible) {
+ if (!state.visible || !ghostedView.isAttachedToWindow) {
if (ghostView.visibility == View.VISIBLE) {
// Making the ghost view invisible will make the ghosted view visible, so order is
// important here.
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index cc33745..82fe3f2 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -24,6 +24,9 @@
import com.android.systemui.multishade.ui.viewmodel.MultiShadeViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import com.android.systemui.util.time.SystemClock
/** The Compose facade, when Compose is *not* available. */
@@ -58,6 +61,14 @@
throwComposeUnavailableError()
}
+ override fun createSceneContainerView(
+ context: Context,
+ viewModel: SceneContainerViewModel,
+ sceneByKey: Map<SceneKey, Scene>,
+ ): View {
+ throwComposeUnavailableError()
+ }
+
private fun throwComposeUnavailableError(): Nothing {
error(
"Compose is not available. Make sure to check isComposeAvailable() before calling any" +
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index 0e79b18..7926f92 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -29,6 +29,11 @@
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.compose.FooterActions
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.scene.ui.composable.SceneContainer
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import com.android.systemui.util.time.SystemClock
/** The Compose facade, when Compose is available. */
@@ -71,4 +76,22 @@
}
}
}
+
+ override fun createSceneContainerView(
+ context: Context,
+ viewModel: SceneContainerViewModel,
+ sceneByKey: Map<SceneKey, Scene>,
+ ): View {
+ return ComposeView(context).apply {
+ setContent {
+ PlatformTheme {
+ SceneContainer(
+ viewModel = viewModel,
+ sceneByKey =
+ sceneByKey.mapValues { (_, scene) -> scene as ComposableScene },
+ )
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index f801434..323fed0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -21,11 +21,14 @@
import android.view.HapticFeedbackConstants
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
@@ -58,6 +61,7 @@
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalView
@@ -67,6 +71,7 @@
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
import com.android.systemui.R
+import com.android.systemui.bouncer.ui.viewmodel.ActionButtonAppearance
import com.android.systemui.bouncer.ui.viewmodel.EnteredKey
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.common.shared.model.ContentDescription
@@ -76,6 +81,7 @@
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -87,78 +93,13 @@
// Report that the UI is shown to let the view-model run some logic.
LaunchedEffect(Unit) { viewModel.onShown() }
- val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
- val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
-
- // Show the failure animation if the user entered the wrong input.
- LaunchedEffect(animateFailure) {
- if (animateFailure) {
- showFailureAnimation()
- viewModel.onFailureAnimationShown()
- }
- }
-
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier,
) {
PinInputDisplay(viewModel)
-
Spacer(Modifier.height(100.dp))
-
- VerticalGrid(
- columns = 3,
- verticalSpacing = 12.dp,
- horizontalSpacing = 20.dp,
- ) {
- repeat(9) { index ->
- val digit = index + 1
- PinButton(
- onClicked = { viewModel.onPinButtonClicked(digit) },
- isEnabled = isInputEnabled,
- ) { contentColor ->
- PinDigit(digit, contentColor)
- }
- }
-
- PinButton(
- onClicked = { viewModel.onBackspaceButtonClicked() },
- onLongPressed = { viewModel.onBackspaceButtonLongPressed() },
- isEnabled = isInputEnabled,
- isIconButton = true,
- ) { contentColor ->
- PinIcon(
- Icon.Resource(
- res = R.drawable.ic_backspace_24dp,
- contentDescription =
- ContentDescription.Resource(R.string.keyboardview_keycode_delete),
- ),
- contentColor,
- )
- }
-
- PinButton(
- onClicked = { viewModel.onPinButtonClicked(0) },
- isEnabled = isInputEnabled,
- ) { contentColor ->
- PinDigit(0, contentColor)
- }
-
- PinButton(
- onClicked = { viewModel.onAuthenticateButtonClicked() },
- isEnabled = isInputEnabled,
- isIconButton = true,
- ) { contentColor ->
- PinIcon(
- Icon.Resource(
- res = R.drawable.ic_keyboard_tab_36dp,
- contentDescription =
- ContentDescription.Resource(R.string.keyboardview_keycode_enter),
- ),
- contentColor,
- )
- }
- }
+ PinPad(viewModel)
}
}
@@ -305,38 +246,153 @@
}
@Composable
-private fun PinDigit(
+private fun PinPad(viewModel: PinBouncerViewModel) {
+ val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
+ val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
+ val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
+ val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+
+ val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } }
+ LaunchedEffect(animateFailure) {
+ // Show the failure animation if the user entered the wrong input.
+ if (animateFailure) {
+ showFailureAnimation(buttonScaleAnimatables)
+ viewModel.onFailureAnimationShown()
+ }
+ }
+
+ VerticalGrid(
+ columns = 3,
+ verticalSpacing = 12.dp,
+ horizontalSpacing = 20.dp,
+ ) {
+ repeat(9) { index ->
+ DigitButton(
+ index + 1,
+ isInputEnabled,
+ viewModel::onPinButtonClicked,
+ buttonScaleAnimatables[index]::value,
+ )
+ }
+
+ ActionButton(
+ icon =
+ Icon.Resource(
+ res = R.drawable.ic_backspace_24dp,
+ contentDescription =
+ ContentDescription.Resource(R.string.keyboardview_keycode_delete),
+ ),
+ isInputEnabled = isInputEnabled,
+ onClicked = viewModel::onBackspaceButtonClicked,
+ onLongPressed = viewModel::onBackspaceButtonLongPressed,
+ appearance = backspaceButtonAppearance,
+ scaling = buttonScaleAnimatables[9]::value,
+ )
+
+ DigitButton(
+ 0,
+ isInputEnabled,
+ viewModel::onPinButtonClicked,
+ buttonScaleAnimatables[10]::value,
+ )
+
+ ActionButton(
+ icon =
+ Icon.Resource(
+ res = R.drawable.ic_keyboard_tab_36dp,
+ contentDescription =
+ ContentDescription.Resource(R.string.keyboardview_keycode_enter),
+ ),
+ isInputEnabled = isInputEnabled,
+ onClicked = viewModel::onAuthenticateButtonClicked,
+ appearance = confirmButtonAppearance,
+ scaling = buttonScaleAnimatables[11]::value,
+ )
+ }
+}
+
+@Composable
+private fun DigitButton(
digit: Int,
- contentColor: Color,
+ isInputEnabled: Boolean,
+ onClicked: (Int) -> Unit,
+ scaling: () -> Float,
) {
- // TODO(b/281878426): once "color: () -> Color" (added to BasicText in aosp/2568972) makes it
- // into Text, use that here, to animate more efficiently.
- Text(
- text = digit.toString(),
- style = MaterialTheme.typography.headlineLarge,
- color = contentColor,
- )
+ PinPadButton(
+ onClicked = { onClicked(digit) },
+ isEnabled = isInputEnabled,
+ backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
+ foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier =
+ Modifier.graphicsLayer {
+ val scale = scaling()
+ scaleX = scale
+ scaleY = scale
+ }
+ ) { contentColor ->
+ // TODO(b/281878426): once "color: () -> Color" (added to BasicText in aosp/2568972) makes
+ // it into Text, use that here, to animate more efficiently.
+ Text(
+ text = digit.toString(),
+ style = MaterialTheme.typography.headlineLarge,
+ color = contentColor(),
+ )
+ }
}
@Composable
-private fun PinIcon(
+private fun ActionButton(
icon: Icon,
- contentColor: Color,
+ isInputEnabled: Boolean,
+ onClicked: () -> Unit,
+ onLongPressed: (() -> Unit)? = null,
+ appearance: ActionButtonAppearance,
+ scaling: () -> Float,
) {
- Icon(
- icon = icon,
- tint = contentColor,
- )
+ val isHidden = appearance == ActionButtonAppearance.Hidden
+ val hiddenAlpha by animateFloatAsState(if (isHidden) 0f else 1f, label = "Action button alpha")
+
+ val foregroundColor =
+ when (appearance) {
+ ActionButtonAppearance.Shown -> MaterialTheme.colorScheme.onSecondaryContainer
+ else -> MaterialTheme.colorScheme.onSurface
+ }
+ val backgroundColor =
+ when (appearance) {
+ ActionButtonAppearance.Shown -> MaterialTheme.colorScheme.secondaryContainer
+ else -> MaterialTheme.colorScheme.surface
+ }
+
+ PinPadButton(
+ onClicked = onClicked,
+ onLongPressed = onLongPressed,
+ isEnabled = isInputEnabled && !isHidden,
+ backgroundColor = backgroundColor,
+ foregroundColor = foregroundColor,
+ modifier =
+ Modifier.graphicsLayer {
+ alpha = hiddenAlpha
+ val scale = scaling()
+ scaleX = scale
+ scaleY = scale
+ }
+ ) { contentColor ->
+ Icon(
+ icon = icon,
+ tint = contentColor(),
+ )
+ }
}
@Composable
-private fun PinButton(
+private fun PinPadButton(
onClicked: () -> Unit,
isEnabled: Boolean,
+ backgroundColor: Color,
+ foregroundColor: Color,
modifier: Modifier = Modifier,
onLongPressed: (() -> Unit)? = null,
- isIconButton: Boolean = false,
- content: @Composable (contentColor: Color) -> Unit,
+ content: @Composable (contentColor: () -> Color) -> Unit,
) {
var isPressed: Boolean by remember { mutableStateOf(false) }
@@ -370,18 +426,16 @@
animateColorAsState(
when {
isPressed -> MaterialTheme.colorScheme.primary
- isIconButton -> MaterialTheme.colorScheme.secondaryContainer
- else -> MaterialTheme.colorScheme.surfaceVariant
+ else -> backgroundColor
},
label = "Pin button container color",
animationSpec = colorAnimationSpec
)
- val contentColor: Color by
+ val contentColor =
animateColorAsState(
when {
isPressed -> MaterialTheme.colorScheme.onPrimary
- isIconButton -> MaterialTheme.colorScheme.onSecondaryContainer
- else -> MaterialTheme.colorScheme.onSurfaceVariant
+ else -> foregroundColor
},
label = "Pin button container color",
animationSpec = colorAnimationSpec
@@ -420,17 +474,46 @@
}
},
) {
- content(contentColor)
+ content(contentColor::value)
}
}
-private fun showFailureAnimation() {
- // TODO(b/282730134): implement.
+private suspend fun showFailureAnimation(
+ buttonScaleAnimatables: List<Animatable<Float, AnimationVector1D>>
+) {
+ coroutineScope {
+ buttonScaleAnimatables.forEachIndexed { index, animatable ->
+ launch {
+ animatable.animateTo(
+ targetValue = pinButtonErrorShrinkFactor,
+ animationSpec =
+ tween(
+ durationMillis = pinButtonErrorShrinkMs,
+ delayMillis = index * pinButtonErrorStaggerDelayMs,
+ easing = Easings.Linear,
+ ),
+ )
+
+ animatable.animateTo(
+ targetValue = 1f,
+ animationSpec =
+ tween(
+ durationMillis = pinButtonErrorRevertMs,
+ easing = Easings.Legacy,
+ ),
+ )
+ }
+ }
+ }
}
private val entryShapeSize = 16.dp
private val pinButtonSize = 84.dp
+private val pinButtonErrorShrinkFactor = 67.dp / pinButtonSize
+private const val pinButtonErrorShrinkMs = 50
+private const val pinButtonErrorStaggerDelayMs = 33
+private const val pinButtonErrorRevertMs = 617
// Pin button motion spec: http://shortn/_9TTIG6SoEa
private val pinButtonPressedDuration = 100.milliseconds
diff --git a/packages/SystemUI/compose/features/tests/AndroidManifest.xml b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
index 2f41ea9..8fe9656 100644
--- a/packages/SystemUI/compose/features/tests/AndroidManifest.xml
+++ b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
@@ -40,11 +40,6 @@
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove" />
- <provider android:name="com.android.keyguard.clock.ClockOptionsProvider"
- android:authorities="com.android.systemui.test.keyguard.clock.disabled"
- android:enabled="false"
- tools:replace="android:authorities"
- tools:node="remove" />
<provider android:name="com.android.systemui.people.PeopleProvider"
android:authorities="com.android.systemui.test.people.disabled"
android:enabled="false"
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 8cba2ab..1443465 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -113,6 +113,7 @@
val logBuffer: LogBuffer? = null,
val keepAllLoaded: Boolean,
subTag: String,
+ var isTransitClockEnabled: Boolean = false,
) {
private val TAG = "${ClockRegistry::class.simpleName} ($subTag)"
interface ClockChangeListener {
@@ -204,6 +205,10 @@
var isClockListChanged = false
for (clock in plugin.getClocks()) {
val id = clock.clockId
+ if (!isTransitClockEnabled && id == "DIGITAL_CLOCK_METRO") {
+ continue
+ }
+
val info =
availableClocks.concurrentGetOrPut(id, ClockInfo(clock, plugin, manager)) {
isClockListChanged = true
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index b6d5ef3..95a9ce9 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -184,6 +184,9 @@
/** Flag denoting AI Wallpapers are enabled in wallpaper picker. */
const val FLAG_NAME_WALLPAPER_PICKER_UI_FOR_AIWP = "wallpaper_picker_ui_for_aiwp"
+ /** Flag denoting transit clock are enabled in wallpaper picker. */
+ const val FLAG_NAME_TRANSIT_CLOCK = "lockscreen_custom_transit_clock"
+
object Columns {
/** String. Unique ID for the flag. */
const val NAME = "name"
diff --git a/packages/SystemUI/docs/clock-plugins.md b/packages/SystemUI/docs/clock-plugins.md
index 2226d79..9cb115a 100644
--- a/packages/SystemUI/docs/clock-plugins.md
+++ b/packages/SystemUI/docs/clock-plugins.md
@@ -1,7 +1,7 @@
# Clock Plugins
-The clock appearing on the lock screen and always on display (AOD) can be
-customized via the ClockProviderPlugin plugin interface.
+The clock appearing on the lock screen and always on display (AOD) can be customized via the
+ClockProviderPlugin plugin interface. The ClockPlugin interface has been removed.
## Lock screen integration
The lockscreen code has two main components, a [clock customization library](../customization), and
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
deleted file mode 100644
index bef61b8..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package com.android.systemui.plugins;
-
-import android.graphics.Bitmap;
-import android.graphics.Paint.Style;
-import android.view.View;
-
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-import java.util.TimeZone;
-
-/**
- * Plugin used to replace main clock in keyguard.
- * @deprecated Migrating to ClockProviderPlugin
- */
-@Deprecated
-@ProvidesInterface(action = ClockPlugin.ACTION, version = ClockPlugin.VERSION)
-public interface ClockPlugin extends Plugin {
-
- String ACTION = "com.android.systemui.action.PLUGIN_CLOCK";
- int VERSION = 5;
-
- /**
- * Get the name of the clock face.
- *
- * This name should not be translated.
- */
- String getName();
-
- /**
- * Get the title of the clock face to be shown in the picker app.
- */
- String getTitle();
-
- /**
- * Get thumbnail of clock face to be shown in the picker app.
- */
- Bitmap getThumbnail();
-
- /**
- * Get preview images of clock face to be shown in the picker app.
- *
- * Preview image should be realistic and show what the clock face will look like on AOD and lock
- * screen.
- *
- * @param width width of the preview image, should be the same as device width in pixels.
- * @param height height of the preview image, should be the same as device height in pixels.
- */
- Bitmap getPreview(int width, int height);
-
- /**
- * Get clock view.
- * @return clock view from plugin.
- */
- View getView();
-
- /**
- * Get clock view for a large clock that appears behind NSSL.
- */
- default View getBigClockView() {
- return null;
- }
-
- /**
- * Returns the preferred Y position of the clock.
- *
- * @param totalHeight Height of the parent container.
- * @return preferred Y position.
- */
- int getPreferredY(int totalHeight);
-
- /**
- * Allows the plugin to clean up resources when no longer needed.
- *
- * Called when the view previously created by {@link ClockPlugin#getView()} has been detached
- * from the view hierarchy.
- */
- void onDestroyView();
-
- /**
- * Set clock paint style.
- * @param style The new style to set in the paint.
- */
- void setStyle(Style style);
-
- /**
- * Set clock text color.
- * @param color A color value.
- */
- void setTextColor(int color);
-
- /**
- * Sets the color palette for the clock face.
- * @param supportsDarkText Whether dark text can be displayed.
- * @param colors Colors that should be used on the clock face, ordered from darker to lighter.
- */
- default void setColorPalette(boolean supportsDarkText, int[] colors) {}
-
- /**
- * Set the amount (ratio) that the device has transitioned to doze.
- * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
- */
- default void setDarkAmount(float darkAmount) {}
-
- /**
- * Notifies that time tick alarm from doze service fired.
- *
- * Implement this method instead of registering a broadcast listener for TIME_TICK.
- */
- default void onTimeTick() {}
-
- /**
- * Notifies that the time zone has changed.
- *
- * Implement this method instead of registering a broadcast listener for TIME_ZONE_CHANGED.
- */
- default void onTimeZoneChanged(TimeZone timeZone) {}
-
- /**
- * Notifies that the time format has changed.
- *
- * @param timeFormat "12" for 12-hour format, "24" for 24-hour format
- */
- default void onTimeFormatChanged(String timeFormat) {}
-
- /**
- * Indicates whether the keyguard status area (date) should be shown below
- * the clock.
- */
- default boolean shouldShowStatusArea() {
- return true;
- }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
index a4b1cee..f83fa33 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
@@ -2,14 +2,18 @@
import android.os.Bundle
import android.util.Log
+import android.view.View
import androidx.annotation.VisibleForTesting
+typealias WeatherTouchAction = (View) -> Unit
+
class WeatherData
constructor(
val description: String,
val state: WeatherStateIcon,
val useCelsius: Boolean,
val temperature: Int,
+ val touchAction: WeatherTouchAction? = null,
) {
companion object {
const val DEBUG = true
@@ -20,7 +24,7 @@
@VisibleForTesting const val TEMPERATURE_KEY = "temperature"
private const val INVALID_WEATHER_ICON_STATE = -1
- fun fromBundle(extras: Bundle): WeatherData? {
+ fun fromBundle(extras: Bundle, touchAction: WeatherTouchAction? = null): WeatherData? {
val description = extras.getString(DESCRIPTION_KEY)
val state =
WeatherStateIcon.fromInt(extras.getInt(STATE_KEY, INVALID_WEATHER_ICON_STATE))
@@ -41,7 +45,8 @@
description = description,
state = state,
useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
- temperature = temperature
+ temperature = temperature,
+ touchAction = touchAction
)
if (DEBUG) {
Log.i(TAG, "Weather data parsed $result from $extras")
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 40f1687..c89855d 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -91,9 +91,9 @@
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM को PIN हाल्नुहोस्।"</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" को SIM को PIN हाल्नुहोस्।"</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> मोबाइल सेवा बिना डिभाइसको प्रयोग गर्न eSIM लाई असक्षम पार्नुहोस्।"</string>
- <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM कार्ड अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड प्रविष्टि गर्नुहोस्। विवरणको लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM <xliff:g id="CARRIER">%1$s</xliff:g> अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड प्रविष्टि गर्नुहोस्। विवरणका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
- <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"रूचाइएको PIN कोड प्रविष्टि गर्नुहोस्"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM कार्ड अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड हाल्नुहोस्। विवरणको लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM <xliff:g id="CARRIER">%1$s</xliff:g> अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड हाल्नुहोस्। विवरणका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"रूचाइएको PIN कोड हाल्नुहोस्"</string>
<string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"रूचाइएको PIN कोड पुष्टि गर्नुहोस्"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="1123048780346295748">"SIM कार्ड अनलक गरिँदै छ…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"४ देखि ८ वटा नम्बर भएको एउटा PIN टाइप गर्नुहोस्।"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index edd3047..badad58 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -348,4 +348,22 @@
<string name="clock_title_analog">Analog</string>
<!-- Title of bouncer when we want to authenticate before continuing with action. [CHAR LIMIT=NONE] -->
<string name="keyguard_unlock_to_continue">Unlock your device to continue</string>
+
+ <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_unattended_update_pin">Enter PIN to install update later</string>
+
+ <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_unattended_update_password">Enter password to install update later</string>
+
+ <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_unattended_update_pattern">Draw pattern to install update later</string>
+
+ <!-- Message shown after an unattended mainline (major) update asking the user to enter their PIN. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_after_update_pin">Device updated. Enter PIN to continue.</string>
+
+ <!-- Message shown after an unattended mainline (major) update asking the user to enter their password. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_after_update_password">Device updated. Enter password to continue.</string>
+
+ <!-- Message shown after an unattended mainline (major) update asking the user to enter their pattern. [CHAR LIMIT=70] -->
+ <string name="kg_prompt_after_update_pattern">Device updated. Draw pattern to continue.</string>
</resources>
diff --git a/packages/SystemUI/res/drawable/android14_patch_adaptive.xml b/packages/SystemUI/res/drawable/android14_patch_adaptive.xml
new file mode 100644
index 0000000..423e351
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android14_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android14_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android14_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android14_patch_monochrome"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/android14_patch_adaptive_background.xml b/packages/SystemUI/res/drawable/android14_patch_adaptive_background.xml
new file mode 100644
index 0000000..afeae4b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android14_patch_adaptive_background.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M0,0 L108,0 L108,108 L0,108 z"
+ android:fillColor="@android:color/system_neutral1_800"/>
+ <path
+ android:pathData="M44.51,43.32L44.86,42.27C47.04,54.48 52.81,86.71 52.81,50.14C52.81,49.99 52.92,49.86 53.06,49.86H55.04C55.18,49.86 55.3,49.98 55.3,50.14C55.27,114.18 44.51,43.32 44.51,43.32Z"
+ android:fillColor="@android:color/system_accent3_400"/>
+ <path
+ android:name="planetary head"
+ android:pathData="M38.81,42.23L33.63,51.21C33.33,51.72 33.51,52.38 34.02,52.68C34.54,52.98 35.2,52.8 35.49,52.28L40.74,43.2C49.22,47 58.92,47 67.4,43.2L72.65,52.28C72.96,52.79 73.62,52.96 74.13,52.65C74.62,52.35 74.79,51.71 74.51,51.21L69.33,42.23C78.23,37.39 84.32,28.38 85.21,17.74H22.93C23.82,28.38 29.91,37.39 38.81,42.23Z"
+ android:fillColor="#ffffff"/>
+ <!-- yes it's an easter egg in a vector drawable -->
+ <path
+ android:name="planetary body"
+ android:pathData="M22.9,0 L85.1,0 L85.1,15.5 L22.9,15.5 z"
+ android:fillColor="#ffffff" />
+ <path
+ android:pathData="M54.96,43.32H53.1C52.92,43.32 52.77,43.47 52.77,43.65V48.04C52.77,48.22 52.92,48.37 53.1,48.37H54.96C55.15,48.37 55.3,48.22 55.3,48.04V43.65C55.3,43.47 55.15,43.32 54.96,43.32Z"
+ android:fillColor="@android:color/system_accent3_400"/>
+ <path
+ android:pathData="M54.99,40.61H53.08C52.91,40.61 52.77,40.75 52.77,40.92V41.56C52.77,41.73 52.91,41.87 53.08,41.87H54.99C55.16,41.87 55.3,41.73 55.3,41.56V40.92C55.3,40.75 55.16,40.61 54.99,40.61Z"
+ android:fillColor="@android:color/system_accent3_400"/>
+ <path
+ android:pathData="M41.49,47.88H40.86V48.51H41.49V47.88Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M44.13,57.08H43.5V57.71H44.13V57.08Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72.29,66.76H71.66V67.39H72.29V66.76Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M59.31,53.41H58.68V54.04H59.31V53.41Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.47,48.19H63.84V48.83H64.47V48.19Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M60.58,59.09H59.95V59.72H60.58V59.09Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M66.95,56.7H65.69V57.97H66.95V56.7Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M44.13,60.71H43.5V61.34H44.13V60.71Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M49.66,51.33H48.4V52.6H49.66V51.33Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M57.78,63.83H56.52V65.09H57.78V63.83Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M61.1,68.57H59.83V69.83H61.1V68.57Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M40.43,53.73H39.16V54.99H40.43V53.73Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M74.47,44H73.21V45.26H74.47V44Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M36.8,64.58H35.54V65.84H36.8V64.58Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android14_patch_adaptive_foreground.xml b/packages/SystemUI/res/drawable/android14_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..ced4305
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android14_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M54.03,33.03C52.99,33.03 52.14,33.86 52.14,34.87V37.14C52.14,37.34 52.3,37.5 52.5,37.5C52.69,37.5 52.85,37.34 52.85,37.14V36.53C52.85,36.14 53.17,35.82 53.56,35.82H54.51C54.9,35.82 55.22,36.14 55.22,36.53V37.14C55.22,37.34 55.38,37.5 55.57,37.5C55.77,37.5 55.93,37.34 55.93,37.14V34.87C55.93,33.86 55.08,33.03 54.03,33.03H54.03Z"
+ android:fillColor="@android:color/system_accent3_400"/>
+ <path
+ android:pathData="M108,0H0V108H108V0ZM54,80.67C68.73,80.67 80.67,68.73 80.67,54C80.67,39.27 68.73,27.33 54,27.33C39.27,27.33 27.33,39.27 27.33,54C27.33,68.73 39.27,80.67 54,80.67Z"
+ android:fillColor="@android:color/system_accent1_400"
+ android:fillType="evenOdd"/>
+ <group>
+ <!-- the text doesn't look great everywhere but you can remove the clip to try it out. -->
+ <clip-path />
+ <path
+ android:pathData="M28.58,32.18L29.18,31.5L33.82,33.02L33.12,33.81L32.15,33.48L30.92,34.87L31.37,35.8L30.68,36.58L28.58,32.18L28.58,32.18ZM31.25,33.18L29.87,32.71L30.51,34.02L31.25,33.18V33.18Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M38,29.76L34.61,28.79L36.23,31.04L35.42,31.62L32.8,27.99L33.5,27.48L36.88,28.45L35.26,26.21L36.08,25.62L38.7,29.25L38,29.76Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39.23,23.87L40.63,23.27C41.79,22.77 43.13,23.28 43.62,24.43C44.11,25.57 43.56,26.89 42.4,27.39L40.99,27.99L39.23,23.87ZM42.03,26.54C42.73,26.24 42.96,25.49 42.68,24.83C42.4,24.17 41.69,23.82 41,24.11L40.51,24.32L41.55,26.75L42.03,26.54Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M45.91,21.43L47.64,21.09C48.47,20.93 49.12,21.41 49.27,22.15C49.38,22.72 49.15,23.14 48.63,23.45L50.57,25.08L49.39,25.31L47.57,23.79L47.41,23.82L47.76,25.63L46.78,25.83L45.91,21.43H45.91ZM47.87,22.86C48.16,22.8 48.34,22.59 48.29,22.34C48.24,22.07 48,21.96 47.71,22.02L47.07,22.14L47.24,22.98L47.87,22.86Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M52.17,22.69C52.19,21.41 53.24,20.39 54.52,20.41C55.8,20.43 56.82,21.49 56.8,22.76C56.78,24.04 55.72,25.06 54.45,25.04C53.17,25.02 52.15,23.96 52.17,22.69ZM55.79,22.75C55.8,22.02 55.23,21.39 54.51,21.38C53.78,21.37 53.19,21.98 53.18,22.7C53.17,23.43 53.73,24.06 54.47,24.07C55.19,24.08 55.78,23.47 55.79,22.75H55.79Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M60,21.01L60.98,21.2L60.12,25.6L59.14,25.41L60,21.01Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M64.3,22.03L65.73,22.58C66.91,23.03 67.51,24.32 67.07,25.49C66.62,26.65 65.31,27.22 64.13,26.77L62.71,26.22L64.3,22.03L64.3,22.03ZM64.46,25.9C65.17,26.17 65.86,25.8 66.12,25.12C66.37,24.45 66.11,23.71 65.4,23.44L64.91,23.25L63.97,25.72L64.46,25.9Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M73.59,27.94L72.94,27.44L73.51,26.69L74.92,27.77L72.2,31.34L71.45,30.76L73.59,27.94Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76.18,33.75L74.69,32.14L75.25,31.62L78.81,31.42L79.4,32.05L77.47,33.85L77.86,34.27L77.22,34.86L76.83,34.44L76.12,35.11L75.47,34.41L76.18,33.75ZM77.72,32.31L76.12,32.4L76.82,33.15L77.72,32.31Z"
+ android:fillColor="#ffffff"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android14_patch_monochrome.xml b/packages/SystemUI/res/drawable/android14_patch_monochrome.xml
new file mode 100644
index 0000000..beef85c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android14_patch_monochrome.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <clip-path
+ android:pathData="M0,0h108v108h-108z"/>
+ <group>
+ <clip-path
+ android:pathData="M22,22h64v64h-64z"/>
+ <path
+ android:pathData="M54,78C67.25,78 78,67.25 78,54C78,40.75 67.25,30 54,30C40.75,30 30,40.75 30,54C30,67.25 40.75,78 54,78Z"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"/>
+ <group>
+ <clip-path
+ android:pathData="M77.5,54C77.5,66.98 66.98,77.5 54,77.5C41.02,77.5 30.5,66.98 30.5,54C30.5,41.02 41.02,30.5 54,30.5C66.98,30.5 77.5,41.02 77.5,54Z"/>
+ <path
+ android:pathData="M61.5,46.06C56.7,47.89 51.4,47.89 46.61,46.06L44.04,50.51C43.49,51.46 42.28,51.79 41.33,51.24C40.39,50.69 40.06,49.48 40.61,48.53L43.06,44.28C37.97,41.03 34.54,35.56 34,29.19L33.88,27.74H74.22L74.1,29.19C73.57,35.56 70.14,41.03 65.04,44.28L67.51,48.56C68.03,49.49 67.71,50.66 66.8,51.21C65.87,51.77 64.65,51.47 64.08,50.54L64.07,50.51L61.5,46.06Z"
+ android:fillColor="#000000"/>
+ </group>
+ <path
+ android:pathData="M51.33,67.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M48.67,62h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M56.67,70h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M56.67,62h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M67.33,62h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M59.33,51.33h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M62,59.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M70,54h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M35.33,56.67h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M35.33,48.67h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M40.67,59.33h2.67v2.67h-2.67z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M46,51.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M43.33,67.33h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M54,54h1.33v1.33h-1.33z"
+ android:fillColor="#000000"/>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 386c9d6..665c612 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -74,7 +74,7 @@
android:layout_height="wrap_content"
android:id="@+id/barrier"
app:barrierDirection="start"
- app:constraint_referenced_ids="statusIcons,privacy_container" />
+ app:constraint_referenced_ids="shade_header_system_icons,privacy_container" />
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
@@ -108,46 +108,39 @@
<include
android:id="@+id/carrier_group"
layout="@layout/shade_carrier_group"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- android:minHeight="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintWidth_min="48dp"
android:layout_width="0dp"
android:layout_height="0dp"
- app:layout_constrainedWidth="true"
android:layout_gravity="end|center_vertical"
android:layout_marginStart="8dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/shade_header_system_icons"
+ app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- app:layout_constraintTop_toTopOf="@id/clock"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
+ app:layout_constraintTop_toTopOf="@id/clock" />
- <com.android.systemui.statusbar.phone.StatusIconContainer
- android:id="@+id/statusIcons"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- android:paddingEnd="@dimen/signal_cluster_battery_padding"
+ <LinearLayout
+ android:id="@+id/shade_header_system_icons"
android:layout_width="wrap_content"
+ app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
android:layout_height="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintStart_toEndOf="@id/carrier_group"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="@id/clock"
+ android:clickable="true"
+ android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- />
+ app:layout_constraintEnd_toEndOf="@id/privacy_container"
+ app:layout_constraintTop_toTopOf="@id/clock">
- <com.android.systemui.battery.BatteryMeterView
- android:id="@+id/batteryRemainingIcon"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- app:layout_constrainedWidth="true"
- app:textAppearance="@style/TextAppearance.QS.Status"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="@id/clock"
- app:layout_constraintBottom_toBottomOf="parent"
- />
+ <com.android.systemui.statusbar.phone.StatusIconContainer
+ android:id="@+id/statusIcons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingEnd="@dimen/signal_cluster_battery_padding" />
+
+ <com.android.systemui.battery.BatteryMeterView
+ android:id="@+id/batteryRemainingIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ app:textAppearance="@style/TextAppearance.QS.Status" />
+ </LinearLayout>
<FrameLayout
android:id="@+id/privacy_container"
diff --git a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
index a2250b1..0fd3c5b 100644
--- a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
+++ b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
@@ -17,7 +17,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="@dimen/qs_tile_height"
+ android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="@dimen/qs_tile_margin_top_bottom"
android:layout_marginBottom="@dimen/qs_tile_margin_top_bottom"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index d710676..e214666 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -132,21 +132,6 @@
android:id="@+id/lock_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <!-- Background protection -->
- <ImageView
- android:id="@+id/lock_icon_bg"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="@drawable/fingerprint_bg"
- android:visibility="invisible"/>
-
- <ImageView
- android:id="@+id/lock_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:scaleType="centerCrop"/>
-
</com.android.keyguard.LockIconView>
<include
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 6601e63..2fde947 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -65,17 +65,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <include layout="@layout/status_bar_expanded"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible" />
-
<!-- Root for all keyguard content. It was previously located within the shade. -->
<com.android.systemui.keyguard.ui.view.KeyguardRootView
android:id="@id/keyguard_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <include layout="@layout/status_bar_expanded"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
+
<include layout="@layout/brightness_mirror_container" />
<com.android.systemui.scrim.ScrimView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 70d0983..71b02bf 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesig is gestaaf"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestig"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestig om te voltooi"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Ontsluit met gesig"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontsluit met gesig. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesig is herken. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesig is herken. Druk die ontsluitikoon om voort te gaan."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Oudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kopstuk"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Gehoortoestelle"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Skakel tans aan …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outo-draai"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan nie stoor nie. Probeer weer."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan nie stoor nie."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gebruik minstens 4 karakters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gebruik minder as <xliff:g id="LENGTH">%1$d</xliff:g> karakters"</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>
<string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kon nie jou batterymeter lees nie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik vir meer inligting"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker nie"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Vingerafdruksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"staaf"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"gaan by toestel in"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Kom meer te wete"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Kom meer te wete by <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Maak <xliff:g id="APPNAME">%1$s</xliff:g> oop"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Die app opgestel is"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Minstens een kaart by Wallet gevoeg is"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Installeer ’n kamera-app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Die app opgestel is"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Minstens een toestel beskikbaar is"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Kies ’n versteknotasapp om die notaneemkortpad te gebruik"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Kies app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Raak en hou kortpad"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Kanselleer"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteitmodus is aan"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent-aandag is aan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 316d762..e2038fb 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"መልክ ተረጋግጧል"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ተረጋግጧል"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ለማጠናቀቅ አረጋግጥን መታ ያድርጉ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"በመልክ ተከፍቷል"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"በመልክ ተከፍቷል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"መልክ ተለይቶ ታውቋል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"መልክ ተለይቶ ታውቋል። ለመቀጠል የመክፈቻ አዶውን ይጫኑ።"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ኦዲዮ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ማዳመጫ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ግቤት"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"መስሚያ አጋዥ መሣሪያዎች"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"በማብራት ላይ..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ማስቀመጥ አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ማስቀመጥ አልተቻለም።"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ቢያንስ 4 ቁምፊዎችን ይጠቀሙ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ከ<xliff:g id="LENGTH">%1$d</xliff:g> የሚያንሱ ቁምፊዎችን ይጠቀሙ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
<string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"የባትሪ መለኪያዎን የማንበብ ችግር"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ለበለጠ መረጃ መታ ያድርጉ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ምንም ማንቂያ አልተቀናበረም"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"የጣት አሻራ ዳሳሽ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ያረጋግጡ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"መሣሪያን ያስገቡ"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"የበለጠ ለመረዳት"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> ላይ የበለጠ ይወቁ"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ይክፈቱ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• መተግበሪያው ተዋቅሯል"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ቢያንስ አንድ ካርድ ወደ Wallet ታክሏል"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• የካሜራ መተግበሪያ ይጫኑ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• መተግበሪያው ተዋቅሯል"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ቢያንስ አንድ መሣሪያ ይገኛል"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"የማስታወሻ አያያዝ አቋራጭን ለመጠቀም ነባሪ የማስታወሻ መተግበሪያ ይምረጡ"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"መተግበሪያ ይምረጡ"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"የይንኩ እና ይያዙ አቋራጭ"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ይቅር"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"የቅድሚያ ሁነታ በርቷል"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"የረዳት ትኩረት በርቷል"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
+ <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6ae9ff4..4d4ee94 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"تمّت مصادقة الوجه."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"تم فتح قفل جهازك عند تقريبه من وجهك."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط للمتابعة."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"تم التعرّف على الوجه. اضغط للمتابعة."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"تم التعرّف على الوجه. للمتابعة، اضغط على رمز فتح القفل."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"سماعة الرأس"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"الإدخال"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعات الأذن الطبية"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"جارٍ التفعيل…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"لا يمكن إجراء الحفظ. يُرجى إعادة المحاولة."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"لا يمكن إجراء الحفظ."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"يجب استخدام 4 أحرف على الأقل."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"يجب استخدام أقل من <xliff:g id="LENGTH">%1$d</xliff:g> حرف."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
<string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"لم يتم ضبط منبّه."</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"مستشعر بصمات الإصبع"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"المصادقة"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"الدخول إلى الجهاز"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"مزيد من المعلومات"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"مزيد من المعلومات على <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"فتح \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• إعداد التطبيق"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• إضافة بطاقة واحدة على الأقل إلى \"محفظة Google\""</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• تثبيت تطبيق كاميرا"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• إعداد التطبيق"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• توفُّر جهاز واحد على الأقل"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"اختَر تطبيقًا تلقائيًا لتدوين الملاحظات لاستخدام اختصار تدوين الملاحظات."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"اختيار تطبيق"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"انقر مع الاستمرار على الاختصار."</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"إلغاء"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"وضع الأولوية مفعّل."</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"ميزة لفت انتباه \"مساعد Google\" مفعّلة."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
+ <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 528be9f..eb07ee3 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"নিশ্চিত কৰিলে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূৰ্ণ কৰিবলৈ নিশ্চিত কৰক-ত টিপক"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিঅ’"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডছেট"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"শ্ৰৱণ যন্ত্ৰ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"অন কৰি থকা হৈছে…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ছেভ কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ছেভ কৰিব নোৱাৰি।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"অতি কমেও ৪ টা বৰ্ণ ব্যৱহাৰ কৰক"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> টাতকৈ কম বৰ্ণ ব্যৱহাৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
<string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"আপোনাৰ বেটাৰী মিটাৰ পঢ়োঁতে সমস্যা হৈছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনো এলাৰ্ম ছেট কৰা হোৱা নাই"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"বিশ্বাসযোগ্যতা প্ৰমাণ কৰক"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইচ আনলক কৰক"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"অধিক জানক"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>ত অধিক জানক"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খোলক"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• এপ্টো ছেট আপ কৰা হৈছে"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Walletত অতি কমেও এখন কাৰ্ড যোগ দিয়া হৈছে"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• এটা কেমেৰা এপ্ ইনষ্টল কৰক"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• এপ্টো ছেট আপ কৰা হৈছে"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• অতি কমেও এটা ডিভাইচ উপলব্ধ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"টোকাগ্ৰহণৰ শ্বৰ্টকাটটো ব্যৱহাৰ কৰিবলৈ এটা ডিফ’ল্ট টোকা লোৱা এপ্ বাছনি কৰক"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"এপ্ বাছনি কৰক"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"শ্বৰ্টকাটটোত স্পৰ্শ কৰি ধৰি ৰাখক"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"বাতিল কৰক"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"অগ্ৰাধিকাৰ দিয়া ম’ড অন আছে"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistantএ আপোনাৰ কথা শুনি আছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
+ <string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 72d2560..a99ea62 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Üz doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Təsdiqləndi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamaq üçün \"Təsdiq edin\" seçiminə toxunun"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Üz ilə kiliddən çıxarılıb"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Üz ilə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Üz tanınıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb davam edin."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Qulaqlıq"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eşitmə aparatları"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Yadda saxlamaq mümkün deyil. Yenə cəhd edin."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Yadda saxlamaq mümkün deyil."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Ən azı 4 simvoldan istifadə edin"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Maksimum <xliff:g id="LENGTH">%1$d</xliff:g> simvol istifadə edin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Siqnal ayarlanmayıb"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Barmaq izi sensoru"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"doğrulayın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz daxil edin"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Ətraflı məlumat"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Ətraflı məlumat: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> tətbiqini açın"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Tətbiq ayarlanmalıdır"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Pulqabına ən azı bir kart əlavə edilməlidir"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kamera tətbiqini quraşdırın"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Tətbiq ayarlanmalıdır"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ən azı bir cihaz əlçatandır"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Qeydgötürmə qısayolu üçün defolt qeyd tətbiqi seçin"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Tətbiq seçin"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Qısayola toxunub saxlayın"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Ləğv edin"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritet rejimi aktivdir"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent aktivdir"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
+ <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 0d0b5fa..1dfdde3 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je potvrđeno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da biste završili"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Otključano je licem"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano je licem. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu otključavanja za nastavak."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključuje se..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Čuvanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Čuvanje nije uspelo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Koristite bar 4 znaka"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Koristite manji broj znakova od <xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nije podešen"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor za otisak prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"potvrdite identitet"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"unesite uređaj"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saznajte više"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saznajte više na <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• da je aplikacija podešena"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• da je u Novčanik dodata barem jedna kartica"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• da ste instalirali aplikaciju za kameru"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• da je aplikacija podešena"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• da je dostupan barem jedan uređaj"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Izaberite podrazumevanu aplikaciju za beleške da biste koristili prečicu za pravljenje beleški"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Izaberi aplikaciju"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Dodirnite i zadržite prečicu"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Otkaži"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetni režim je uključen"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Pomoćnik je u aktivnom stanju"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ba8c998..05841dc 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Твар распазнаны"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Пацверджана"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Націсніце \"Пацвердзіць\", каб завяршыць"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Разблакіравана распазнаваннем твару"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблакіравана распазнаваннем твару. Націсніце для працягу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Твар распазнаны. Націсніце для працягу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Твар распазнаны. Для працягу націсніце значок разблакіроўкі."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Гук"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Увод"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слыхавыя апараты"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Уключэнне…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не ўдалося захаваць. Паўтарыце спробу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не ўдалося захаваць."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Скарыстайце не менш як 4 сімвалы"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Колькасць сімвалаў павінна быць меншай за <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
<string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма будзільнікаў"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер адбіткаў пальцаў"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"правесці аўтэнтыфікацыю"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"адкрыць галоўны экран прылады"</string>
@@ -1111,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Памочнік слухае"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Стварэнне нататак"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Стварэнне нататак, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Перадача даных"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string>
@@ -1130,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Даведацца больш"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Даведайцеся больш на старонцы <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Адкрыць праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Праграма наладжана."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• У Кашалёк дададзена хаця б адна картка."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Усталявана праграма \"Камера\"."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Праграма наладжана."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Даступная хаця б адна прылада."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Выберыце стандартную праграму для нататак, каб карыстацца хуткай камандай для нататак"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Выберыце праграму"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Дакраніцеся і ўтрымлівайце ярлык"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Скасаваць"</string>
@@ -1164,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Прыярытэтны рэжым уключаны"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Памочнік гатовы выконваць каманды"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
+ <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 69f08ec..0345471 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е удостоверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потвърдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Докоснете „Потвърждаване“ за завършване"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Отключено с лице"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отключено с лице. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето бе разпознато. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето бе разпознато. Продължете чрез иконата за отключване."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Вход"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухови апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включва се..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авт. ориентация"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се запази. Опитайте отново."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се запази."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Използвайте поне 4 знака"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Използвайте по-малко от <xliff:g id="LENGTH">%1$d</xliff:g> знака"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Възникна проблем при четенето на данните за нивото на батерията"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма зададен будилник"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отпечатъци"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"удостоверяване"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"вход в устройството"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Научете повече"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Научете повече на адрес <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отваряне на <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Приложението е настроено."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• В Wallet е добавена поне една карта."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Инсталирано е приложение за камера."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Приложението е настроено."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Налице е поне едно устройство."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Изберете стандартно приложение за бележки, за да използвате прекия път за водене на бележки"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Избиране на приложение"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Докоснете и задръжте прекия път"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Отказ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетният режим е включен"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Функцията за активиране на Асистент е включена"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
+ <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f2eb8ca..2d0388d 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ফেস যাচাই করা হয়েছে"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"কনফার্ম করা হয়েছে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূর্ণ করতে \'কনফার্ম করুন\' বোতামে ট্যাপ করুন"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ফেস দেখিয়ে আনলক করা হয়েছে"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে আনলক আইকন প্রেস করুন।"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিও"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডসেট"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"হিয়ারিং এড"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"চালু করা হচ্ছে…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"সেভ করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"সেভ করা যাচ্ছে না।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"কমপক্ষে ৪টি অক্ষর ব্যবহার করুন"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>টির চেয়ে কম অক্ষর ব্যবহার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
<string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনও অ্যালার্ম সেট করা নেই"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ফিঙ্গারপ্রিন্ট সেন্সর"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"যাচাই করিয়ে নিন"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইস আনলক করুন"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"আরও জানুন"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"আরও জানতে <xliff:g id="URL">%s</xliff:g>-এ যান"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খুলুন"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• অ্যাপ সেট-আপ করা হয়ে গেছে"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• অন্তত একটি কার্ড Wallet-এ যোগ করা হয়েছে"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ক্যামেরা অ্যাপ ইনস্টল করুন"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• অ্যাপ সেট-আপ করা হয়ে গেছে"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• অন্তত একটি ডিভাইস উপলভ্য"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"নোট নেওয়ার শর্টকাট ব্যবহার করতে, ডিফল্ট কোনও নোট অ্যাপ বেছে নিন"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"অ্যাপ বেছে নিন"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"শর্টকাট টাচ করে ধরে রাখুন"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"বাতিল করুন"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\'প্রায়োরিটি\' মোড চালু করা আছে"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"অ্যাসিস্ট্যান্ট আপনার কথা শোনার জন্য চালু করা আছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
+ <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 25a212d..8e8fb8b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je provjereno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da završite"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Otključano je licem"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano licem. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice prepoznato. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu za otklj. da nastavite."</string>
@@ -244,7 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ulaz"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nije moguće sačuvati. Pokušajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nije moguće sačuvati."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Koristite najmanje 4 znaka"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Koristite manje od <xliff:g id="LENGTH">%1$d</xliff:g> znak(ov)a"</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>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -1048,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nema nijednog alarma"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor za otisak prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificiranje"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristup uređaju"</string>
@@ -1127,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saznajte više"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saznajte više na <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvori aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikacija je postavljena"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Najmanje jedna kartica je dodana u Novčanik"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Instalirajte aplikaciju kamere"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikacija je postavljena"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Dostupan je najmanje jedan uređaj"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Odaberite zadanu aplikaciju za bilješke da koristite prečicu za zapisivanje bilješki"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Za dodavanje aplikacije Wallet kao prečaca provjerite je li instalirana"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Provjerite je li dodana barem jedna kartica kako biste dodali aplikaciju Wallet kao prečac"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Provjerite je li instalirana aplikacija kamere kako biste dodali čitač QR koda kao prečac"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Provjerite je li aplikacija Home instalirana kako biste je dodali kao prečac"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostupan je najmanje jedan uređaj"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Odaberite zadanu aplikaciju za bilješke da biste koristili prečac za pisanje bilježaka"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Odaberi aplikaciju"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Dodirnite i zadržite prečicu"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Otkaži"</string>
@@ -1161,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Način rada Prioriteti je uključen"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Pažnja Asistenta je uključena"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9758360..530482f 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirma per completar"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"S\'ha desbloquejat amb la cara"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"S\'ha reconegut la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"S\'ha reconegut la cara. Prem la icona per continuar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiòfons"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"S\'està activant…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No es pot desar. Torna-ho a provar."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No es pot desar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilitza 4 caràcters com a mínim"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilitza menys de <xliff:g id="LENGTH">%1$d</xliff:g> caràcters"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca per obtenir més informació"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Cap alarma definida"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor d\'empremtes digitals"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedir al dispositiu"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Més informació"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Més informació a <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Obre <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• L\'aplicació està configurada."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Almenys s\'ha afegit una targeta a Wallet."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Tens una aplicació de càmera."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• L\'aplicació està configurada."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Almenys un dispositiu està disponible."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecciona una aplicació de notes predeterminada per utilitzar la drecera de presa de notes"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Selecciona una aplicació"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantén premuda la drecera"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel·la"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El mode Prioritat està activat"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'Assistent està activat"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ba275ea..fba856d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Obličej byl ověřen"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrzeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ověření dokončíte klepnutím na Potvrdit"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Odemknuto obličejem"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odemknuto obličejem. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obličej rozpoznán. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Sluchátka"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Naslouchátka"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
@@ -308,7 +306,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
- <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Záznam obrazovky"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekordér obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Spustit"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončit"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string>
@@ -420,7 +418,7 @@
<string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nové"</string>
- <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tichá oznámení"</string>
+ <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tichý režim"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string>
@@ -564,7 +562,7 @@
<string name="inline_done_button" msgid="6043094985588909584">"Hotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Použít"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Vypnout oznámení"</string>
- <string name="notification_silence_title" msgid="8608090968400832335">"Tiché"</string>
+ <string name="notification_silence_title" msgid="8608090968400832335">"Tichý režim"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Výchozí"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žádný zvuk ani vibrace"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Uložení se nezdařilo. Zkuste to znovu."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Uložení se nezdařilo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Heslo musí mít alespoň 4 znaky"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Použijte méně než <xliff:g id="LENGTH">%1$d</xliff:g> znaků"</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>
<string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Budík nenastaven"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Snímač otisků prstů"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ověříte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"zadáte zařízení"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Další informace"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Další informace najdete na adrese <xliff:g id="URL">%s</xliff:g>."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otevřít <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikace je nastavena"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Do Peněženky byla přidána alespoň jedna karta"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Je nainstalována aplikace pro fotoaparát"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikace je nastavena"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Je k dispozici alespoň jedno zařízení"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Vyberte výchozí aplikaci k psaní poznámek, ke které přidružíte zkratku pro poznámky"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Vyberte aplikaci"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Podržte zkratku"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Zrušit"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Režim priority je zapnutý"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Pozornost Asistenta je zapnutá"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
+ <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 4a1654a..386f809 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansigtet er godkendt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekræftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tryk på Bekræft for at udføre"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Låst op via ansigtsgenkendelse"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst op ved hjælp af ansigt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansigt genkendt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansigt genkendt. Tryk på oplåsningsikonet for at fortsætte."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverer…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Der kan ikke gemmes. Prøv igen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Der kan ikke gemmes."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Angiv mindst 4 tegn"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Angiv færre end <xliff:g id="LENGTH">%1$d</xliff:g> tegn"</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>
<string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at læse dit batteriniveau"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm er indstillet"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeraftrykssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"godkende"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"få adgang til enheden"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Få flere oplysninger"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Få flere oplysninger på <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åbn <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Appen er konfigureret"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Mindst ét kort er føjet til Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Installer en kameraapp"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Appen er konfigureret"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Mindst én enhed er tilgængelig"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Vælg en standardapp til noter for at bruge genvejen til notetagning"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Vælg app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Hold fingeren på genvejen"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuller"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetstilstand er aktiveret"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent lytter"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installer app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2cfcb4f..b57f023 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesicht authentifiziert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bestätigt"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Zum Abschließen auf \"Bestätigen\" tippen"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Mit Gesicht entsperrt"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Gerät mit dem Gesicht entsperrt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesicht erkannt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesicht erkannt. Tippe zum Fortfahren auf das Symbol „Entsperren“."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Eingabe"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörgerät"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Wird aktiviert…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
@@ -454,9 +452,9 @@
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA-Zertifikate"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Richtlinien ansehen"</string>
<string name="monitoring_button_view_controls" msgid="8316440345340701117">"Jugendschutzeinstellungen"</string>
- <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_named_management" msgid="505833016545056036">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nIhr IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten Ihres Geräts sehen und verwalten.\n\nWeitere Informationen erhalten Sie von Ihrem IT-Administrator."</string>
<string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> kann möglicherweise auf die Daten zugreifen, die mit diesem Gerät verknüpft sind, Apps verwalten und die Geräteeinstellungen ändern.\n\nFalls du Fragen hast, wende dich an <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</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" msgid="4308879039175729014">"Dieses Gerät gehört Ihrer Organisation.\n\nIhr IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten Ihres Geräts sehen und verwalten.\n\nWeitere Informationen erhalten Sie von Ihrem 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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle in deinem Arbeitsprofil installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Auf dem Gerät ist das Zertifikat einer Zertifizierungsstelle installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Speichern nicht möglich. Versuche es noch einmal."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Speichern nicht möglich."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gib mindestens vier Zeichen ein"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Maximal <xliff:g id="LENGTH">%1$d</xliff:g> Zeichen möglich"</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>
<string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Für weitere Informationen tippen"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Kein Wecker gestellt"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerabdrucksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authentifizieren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Eingeben des Geräts"</string>
@@ -1111,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant hört zu"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Notizen"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notizen, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Übertragung läuft"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
@@ -1130,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Weitere Informationen"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Weitere Informationen unter <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> öffnen"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Die App ist eingerichtet"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet wurde mindestens eine Karte hinzugefügt"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kamera-App ist installiert"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Die App ist eingerichtet"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Mindestens ein Gerät ist verfügbar"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Wähle eine Standard-App für Notizen aus, die du für die Verknüpfung verwenden möchtest"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"App wählen"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Verknüpfung berühren & halten"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Abbrechen"</string>
@@ -1164,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritätsmodus an"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant-Aktivierung an"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
+ <string name="install_app" msgid="5066668100199613936">"App installieren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 56e8fb7..421307ee 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Επιβεβαιώθηκε"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Πατήστε Επιβεβαίωση για ολοκλήρωση"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Ξεκλειδώθηκε με αναγνώριση προσώπου"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Το πρόσωπο αναγνωρ. Πατήστε το εικον. ξεκλειδ. για συνέχεια."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ήχος"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ακουστικά"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Είσοδος"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Βοηθήματα ακοής"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ενεργοποίηση…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Δεν είναι δυνατή η αποθήκευση. Δοκιμάστε ξανά."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Δεν είναι δυνατή η αποθήκευση."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Χρησιμοποιήστε τουλάχιστον 4 χαρακτήρες"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Χρησιμοποιήστε λιγότερους από <xliff:g id="LENGTH">%1$d</xliff:g> χαρακτήρες"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
<string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Δεν ορίστηκε ξυπνητ."</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Αισθητήρας δακτυλικών αποτυπωμάτων"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"έλεγχος ταυτότητας"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"εισαγωγή συσκευής"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Μάθετε περισσότερα"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Μάθετε περισσότερα στο <xliff:g id="URL">%s</xliff:g>."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Άνοιγμα <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Η εφαρμογή έχει ρυθμιστεί"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Έχει προστεθεί τουλάχιστον μία κάρτα στο Πορτοφόλι"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Εγκαταστήσατε μια εφαρμογή κάμερας"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Η εφαρμογή έχει ρυθμιστεί"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Είναι διαθέσιμη τουλάχιστον μία συσκευή"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Επιλέξτε μια προεπιλεγμένη εφαρμογή σημειώσεων για να χρησιμοποιήσετε τη συντόμευση δημιουργίας σημειώσεων"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Επιλογή εφαρμογής"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Παρατεταμένο άγγιγμα συντόμευσης"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Ακύρωση"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Η λειτουργία προτεραιότητας είναι ενεργοποιημένη"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Ο Βοηθός βρίσκεται σε αναμονή"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
+ <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 3cdfccb..eb4ccf5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Unlocked by face"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -451,11 +450,11 @@
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
<string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Network logging"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA certificates"</string>
- <string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</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_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> may be able to access data associated with this device, manage apps and change this device\'s settings.\n\nIf you have questions, contact <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</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" 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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Your organisation installed a certificate authority in your work profile. Your secure network traffic may be monitored or modified."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"A certificate authority is installed on this device. Your secure network traffic may be monitored or modified."</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</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="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1048,6 +1046,8 @@
<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>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1127,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• At least one card has been added to Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Install a camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• At least one device is available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Select a default notes app to use the note-taking shortcut"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Select app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Touch & hold shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel"</string>
@@ -1161,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Install app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 23d399e..43d58ca 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -450,11 +450,11 @@
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
<string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Network logging"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA certificates"</string>
- <string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</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_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_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> may be able to access data associated with this device, manage apps, and change this devices settings.\n\nIf you have questions, contact <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</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" 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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Your organization installed a certificate authority in your work profile. Your secure network traffic may be monitored or modified."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"A certificate authority is installed on this device. Your secure network traffic may be monitored or modified."</string>
@@ -1004,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least 4 characters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</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="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1047,6 +1046,7 @@
<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>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1126,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• At least one card has been added to Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Install a camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• At least one device is available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Select a default notes app to use the notetaking shortcut"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure the app is installed"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure at least one card has been added"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure a camera app is installed"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure the app is installed"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the notetaking shortcut"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Select app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Touch and hold shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel"</string>
@@ -1160,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Install app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 3cdfccb..eb4ccf5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Unlocked by face"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -451,11 +450,11 @@
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
<string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Network logging"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA certificates"</string>
- <string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</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_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> may be able to access data associated with this device, manage apps and change this device\'s settings.\n\nIf you have questions, contact <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</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" 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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Your organisation installed a certificate authority in your work profile. Your secure network traffic may be monitored or modified."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"A certificate authority is installed on this device. Your secure network traffic may be monitored or modified."</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</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="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1048,6 +1046,8 @@
<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>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1127,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• At least one card has been added to Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Install a camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• At least one device is available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Select a default notes app to use the note-taking shortcut"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Select app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Touch & hold shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel"</string>
@@ -1161,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Install app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 3cdfccb..eb4ccf5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Unlocked by face"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -451,11 +450,11 @@
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
<string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Network logging"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA certificates"</string>
- <string name="monitoring_button_view_policies" msgid="3869724835853502410">"View Policies"</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_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> may be able to access data associated with this device, manage apps and change this device\'s settings.\n\nIf you have questions, contact <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</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" 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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Your organisation installed a certificate authority in your work profile. Your secure network traffic may be monitored or modified."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"A certificate authority is installed on this device. Your secure network traffic may be monitored or modified."</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</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="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1048,6 +1046,8 @@
<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>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"Authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1127,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• At least one card has been added to Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Install a camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• At least one device is available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Select a default notes app to use the note-taking shortcut"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Select app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Touch & hold shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel"</string>
@@ -1161,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Install app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 112d0bd..b4c5d10 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1004,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least 4 characters"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use fewer than <xliff:g id="LENGTH">%1$d</xliff:g> characters"</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="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1047,6 +1046,7 @@
<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>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No alarm set"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"enter screen lock"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingerprint sensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"enter device"</string>
@@ -1126,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Learn more"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Learn more at <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• At least one card has been added to Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Install a camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• The app is set up"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• At least one device is available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Select a default notes app to use the notetaking shortcut"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"To add the Wallet app as a shortcut, make sure the app is installed"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"To add the Wallet app as a shortcut, make sure at least one card has been added"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"To add the QR code scanner as a shortcut, make sure a camera app is installed"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"To add the Home app as a shortcut, make sure the app is installed"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• At least one device is available"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Select a default notes app to use the notetaking shortcut"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Select app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Touch & hold shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancel"</string>
@@ -1160,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
+ <string name="install_app" msgid="5066668100199613936">"Install app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index bd75476..5358a26 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Se autenticó el rostro"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Se desbloqueó con el rostro"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueo con rostro. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rostro reconocido. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rostro reconocido. Presiona el desbloqueo para continuar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
@@ -538,7 +536,7 @@
<string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Actualizando"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
- <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
+ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de la pantalla de bloqueo"</string>
<string name="qr_code_scanner_title" msgid="1938155688725760702">"Escáner de código QR"</string>
<string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Vuelve a intentarlo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa al menos 4 caracteres"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No establecida"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas dactilares"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ingresar al dispositivo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Más información"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Más información en <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Se configuró la app."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Se agregó al menos una tarjeta a la Billetera."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Se instaló la app de Cámara."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Se configuró la app."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Hay al menos un dispositivo disponible."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecciona una app de notas predeterminada para usar el atajo de toma de notas"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para agregar la app de Billetera como acceso directo, asegúrate de haber instalado la app"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para agregar la app de Billetera como acceso directo, asegúrate de haber agregado al menos una tarjeta"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para agregar el escáner de código QR como acceso directo, asegúrate de haber instalado la app de la cámara"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para agregar la app de Home como acceso directo, asegúrate de haber instalado la app"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Hay al menos un dispositivo disponible"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecciona una app de notas predeterminada para usar el acceso directo de toma de notas"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Seleccionar app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantener presionado atajo"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El modo de prioridad está activado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistente está prestando atención"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 37d1d18..42e390d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar la acción"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Desbloqueado con la cara"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado con la cara. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Cara reconocida. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Cara reconocida. Pulsa el icono de desbloquear para continuar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Inténtalo de nuevo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa 4 caracteres como mínimo"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca la pantalla para consultar más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ninguna alarma puesta"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de huellas digitales"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticarte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acceder al dispositivo"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Más información"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Más información en <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• La aplicación debe estar configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Se debe haber añadido al menos una tarjeta a Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Debes instalar una aplicación de cámara"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• La aplicación debe estar configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Al menos un dispositivo debe estar disponible"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecciona una aplicación de notas predeterminada para usar el acceso directo de toma de notas"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Seleccionar aplicación"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantén pulsado el acceso directo"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridad activado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"El Asistente está activado"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5936e42..cd6b47c 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Nägu on autenditud"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kinnitatud"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lõpuleviimiseks puudutage nuppu Kinnita"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Avati näoga"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avati näoga. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nägu tuvastati. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nägu tuvastati. Jätkamiseks vajutage avamise ikooni."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Heli"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Peakomplekt"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sisend"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuuldeaparaadid"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ei saa salvestada. Proovige uuesti."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ei saa salvestada."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Kasutage vähemalt 4 tähemärki"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kasutage vähem kui <xliff:g id="LENGTH">%1$d</xliff:g> tähemärki"</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>
<string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Puudutage lisateabe saamiseks"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Äratust pole"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sõrmejäljeandur"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentimiseks"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"seadmesse sisenemiseks"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Lisateave"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Lisateave: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ava <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Rakendus on seadistatud"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Vähemalt üks kaart on Walletisse lisatud"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Installige kaamerarakendus"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Rakendus on seadistatud"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Vähemalt üks seade on saadaval"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Valige märkmete tegemise vaikerakendus, et kasutada märkmete tegemise otseteed"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Valige rakendus"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pikalt puudutamise otsetee"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Tühista"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteetne režiim on sisse lülitatud"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent on aktiveeritud"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
+ <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 26cebd5..a670166 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autentifikatu da aurpegia"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Berretsita"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Amaitzeko, sakatu \"Berretsi\""</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Aurpegiaren bidez desblokeatu da"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ezagutu da aurpegia. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ezagutu da aurpegia. Aurrera egiteko, sakatu desblokeatzeko ikonoa."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Entzungailua"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sarrera"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audifonoak"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktibatzen…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ezin da gorde. Saiatu berriro."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ezin da gorde."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Erabili lau karaktere gutxienez"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Erabili <xliff:g id="LENGTH">%1$d</xliff:g> karaktere baino gutxiago"</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>
<string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat izan da bateria-neurgailua irakurtzean"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ez da ezarri alarmarik"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Hatz-marken sentsorea"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"sartu gailuan"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Lortu informazio gehiago"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Lortu informazio gehiago <xliff:g id="URL">%s</xliff:g> helbidean"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ireki <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikazioa konfiguratuta dago."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Diru-zorroa zerbitzuan gutxienez txartel bat gehitu da."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kamera-aplikazio bat instalatu da."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikazioa konfiguratuta dago."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Gutxienez gailu bat erabilgarri dago."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Oharrak idazteko lasterbidea erabiltzeko, hautatu oharretarako aplikazio lehenetsia."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Hautatu aplikazioa"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Eduki sakatuta lasterbidea"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Utzi"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Lehentasun modua aktibatuta dago"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Laguntzailea zerbitzuak arreta jarrita dauka"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 09a802f..dc24a3d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چهره اصالتسنجی شد"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تأیید شد"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"برای تکمیل، روی تأیید ضربه بزنید"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"قفل با چهره باز شد"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"قفلْ با چهره باز شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چهره شناسایی شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چهره شناسایی شد. برای ادامه، نماد قفلگشایی را فشار دهید."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"هدست"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ورودی"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سمعک"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"روشن کردن…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحهنمایش"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ذخیره نشد. دوباره امتحان کنید."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ذخیره نشد."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"حداقل از ۴ نویسه استفاده کنید"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"از کمتر از <xliff:g id="LENGTH">%1$d</xliff:g> نویسه استفاده کنید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریدهدان کپی شد."</string>
<string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"حسگر اثرانگشت"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"اصالتسنجی کردن"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"وارد شدن به دستگاه"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"بیشتر بدانید"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"در <xliff:g id="URL">%s</xliff:g> اطلاعات بیشتری دریافت کنید"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"باز کردن <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• برنامه راهاندازی شده باشد"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• حداقل یک کارت به «کیف پول» اضافه شده باشد"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• برنامه دوربین نصب شده باشد"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• برنامه راهاندازی شده باشد"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• حداقل یک دستگاه دردسترس باشد"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"برنامه یادداشت پیشفرضی را برای میانبر یادداشتبرداری انتخاب کنید"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"برای افزودن برنامه «کیف پول» بهعنوان میانبر، مطمئن شوید این برنامه نصب شده باشد"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"برای افزودن برنامه «کیف پول» بهعنوان میانبر، مطمئن شوید حداقل یک کارت اضافه شده باشد"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"برای افزودن «کدخوان پاسخسریع» بهعنوان میانبر، مطمئن شوید برنامه دوربین نصب شده باشد"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"برای افزودن برنامه Home بهعنوان میانبر، مطمئن شوید این برنامه نصب شده باشد"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• حداقل یک دستگاه دردسترس باشد"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"برای استفاده از میانبر یادداشتبرداری، برنامه یادداشت پیشفرضی را انتخاب کنید"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"انتخاب برنامه"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"میانبر را لمس کنید و نگه دارید"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"لغو کردن"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"حالت اولویت روشن است"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"توجه «دستیار» روشن است"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
+ <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dcc193b..b6303da 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Kasvot tunnistettu"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Vahvistettu"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Valitse lopuksi Vahvista"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Avattu kasvojen avulla"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avattu kasvojen avulla. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Kasvot tunnistettu. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ääni"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Syöttölaite"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuulolaitteet"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Otetaan käyttöön…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tallennus ei onnistu. Yritä uudelleen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tallennus ei onnistu."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Käytä vähintään 4 merkkiä"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Käytä alle <xliff:g id="LENGTH">%1$d</xliff:g> merkkiä"</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>
<string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Saat lisätietoja napauttamalla"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ei herätyksiä"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sormenjälkitunnistin"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"todentaaksesi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"avataksesi laitteen"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Lue lisää"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Lue lisää: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Avaa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Sovellus on otettu käyttöön"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Ainakin yksi kortti on lisätty Walletiin"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Asenna kamerasovellus"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Sovellus on otettu käyttöön"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ainakin yksi laite on käytettävissä"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Valitse muistiinpanojen tekemisen oletussovellus, jota käytetään pikanäppäimen avulla"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Valitse sovellus"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Kosketa pikakuvaketta pitkään"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Peru"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tärkeät-tila on päällä"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant on aktiivinen"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
+ <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d53a390..d88c9e0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Touchez Confirmer pour terminer"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Déverrouillé avec le visage"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverr. par reconnaissance faciale. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur Déverrouiller pour continuer."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Écouteurs"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Prothèses auditives"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilisez au moins 4 caractères"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilisez moins de <xliff:g id="LENGTH">%1$d</xliff:g> caractères"</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>
<string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Aucune alarme définie"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Capteur d\'empreintes digitales"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"En savoir plus"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"En savoir plus : <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• que cette application est configurée;"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• qu\'au moins une carte a été ajoutée à Portefeuille."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• qu\'une application de caméra est installée;"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• que cette application est configurée;"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• qu\'au moins un appareil est utilisable;"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Sélectionnez une application de prise de notes par défaut pour utiliser le raccourci de prise de notes"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Sélectionner l\'application"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Maintenir le doigt sur raccourci"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuler"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Priorité activé"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant à l\'écoute"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 935a465..b4cfb34 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Appuyez sur \"Confirmer\" pour terminer"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Déverrouillé par le visage"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverrouillé par visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour continuer."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Casque"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Appareils auditifs"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilisez au moins quatre caractères"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utilisez moins de <xliff:g id="LENGTH">%1$d</xliff:g> caractères"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Pas d\'alarme définie"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Lecteur d\'empreinte digitale"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"s\'authentifier"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accéder à l\'appareil"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"En savoir plus"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Pour en savoir plus, rendez-vous sur <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• L\'appli est configurée"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Au moins une carte a été ajoutée à Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Installer une appli d\'appareil photo"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• L\'appli est configurée"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Au moins un appareil est disponible"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Sélectionnez une appli de notes par défaut pour utiliser le raccourci de prise de notes"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pour ajouter l\'appli Wallet comme raccourci, vérifiez que l\'appli est installée"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pour ajouter l\'appli Wallet comme raccourci, assurez-vous qu\'au moins une carte a été ajoutée"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pour ajouter le lecteur de code QR comme raccourci, assurez-vous qu\'une appli d\'appareil photo est installée"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pour ajouter l\'application Home comme raccourci, vérifiez que l\'appli est installée"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Au moins un appareil est disponible"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une appli de notes par défaut pour utiliser le raccourci de prise de notes"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Sélectionner une appli"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Appuyez de manière prolongée sur raccourci"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuler"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Prioritaire activé"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant à l\'écoute"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 307e347..014d8ba 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -98,7 +98,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Engadir a unha nota"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
- <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
+ <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación de actividade en curso sobre unha sesión de gravación de pantalla"</string>
<string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"Queres iniciar a gravación?"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"Durante a gravación, Android ten acceso a todo o que se vexa na pantalla ou se reproduza no teu dispositivo. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"Durante a gravación dunha aplicación, Android ten acceso a todo o que se vexa ou se reproduza nela. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autenticouse a cara"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar o proceso"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Usouse o desbloqueo facial"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Usouse o desbloqueo facial. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Recoñeceuse a cara. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Recoñeceuse a cara. Preme a icona de desbloquear."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiófonos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Non se puido gardar a información. Téntao de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Non se pode gardar a información."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utiliza como mínimo 4 caracteres"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Utiliza menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Sen alarmas postas"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impresión dixital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"poñer o dispositivo"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Máis información"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Máis información en <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• A aplicación debe estar configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Ten que haber polo menos unha tarxeta engadida a Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Debes instalar a aplicación de cámara"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• A aplicación debe estar configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ten que haber polo menos un dispositivo dispoñible"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecciona unha aplicación de notas predeterminada para usar o atallo de tomar notas"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Seleccionar aplicación"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantén premido o atallo"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"O modo de prioridade está activado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"A atención do Asistente está activada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 4b5d6e5..cd264e2 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ચહેરાનું પ્રમાણીકરણ થયું"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"પુષ્ટિ કરી"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"પરીક્ષણ પૂર્ણ કરવા કન્ફર્મ કરોને ટૅપ કરો"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ચહેરા દ્વારા અનલૉક કર્યું"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ચહેરા દ્વારા અનલૉક કર્યું. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ચહેરો ઓળખ્યો. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ચહેરો ઓળખ્યો. આગળ વધવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ઑડિયો"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"હૅડસેટ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ઇનપુટ"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"સાંભળવામાં મદદ આપતા યંત્રો"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ચાલુ કરી રહ્યાં છીએ…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ઑટો રોટેટ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ઑટો રોટેટ સ્ક્રીન"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"સાચવી શકતા નથી. ફરી પ્રયાસ કરો."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"સાચવી શકતા નથી."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ઓછામાં ઓછા 4 અક્ષરનો ઉપયોગ કરો"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> કરતાં ઓછા અક્ષરનો ઉપયોગ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
<string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"કોઈ અલાર્મ સેટ નથી"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ફિંગરપ્રિન્ટ સેન્સર"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ખાતરી કરો"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ડિવાઇસ અનલૉક કરો"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"વધુ જાણો"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> પરથી વધુ જાણો"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ખોલો"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ઍપનું સેટઅપ કરેલું છે"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ઓછામાં ઓછું એક કાર્ડ વૉલેટમાં ઉમેરેલું છે"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• કૅમેરા ઍપ ઇન્સ્ટૉલ કરી છે"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ઍપનું સેટઅપ કરેલું છે"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ઓછામાં ઓછું એક ડિવાઇસ ઉપલબ્ધ છે"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"નોંધ લેવાના શૉર્ટકટનો ઉપયોગ કરવા માટે, નોંધ લેનારી કોઈ ડિફૉલ્ટ ઍપ પસંદ કરો"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઓછામાં ઓછું એક કાર્ડ ઉમેરવામાં આવ્યું હોય"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR કોડ સ્કૅનરને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે કૅમેરા ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ઍપને શૉર્ટકટ તરીકે ઉમેરવા માટે, ખાતરી કરો કે ઍપ ઇન્સ્ટૉલ કરેલી હોય"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ઓછામાં ઓછું એક ડિવાઇસ ઉપલબ્ધ છે"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"નોંધ લેવાના શૉર્ટકટનો ઉપયોગ કરવા માટે, નોંધ માટેની ડિફૉલ્ટ ઍપ પસંદ કરો"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ઍપ પસંદ કરો"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"શૉર્ટકટને ટચ વડે પળભર દબાવી રાખો"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"રદ કરો"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"પ્રાધાન્યતા મોડ ચાલુ છે"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant સક્રિય છે"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
+ <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8e95012..e5c798b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -244,8 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"कान की मशीनें"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ब्लूटूथ चालू हो रहा है…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
@@ -1006,8 +1005,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव नहीं किया जा सका. फिर से कोशिश करें."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव नहीं किया जा सका."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"कम से कम चार वर्ण इस्तेमाल करें"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वर्ण से कम इस्तेमाल करें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
<string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
@@ -1049,6 +1047,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"कोई अलार्म सेट नहीं है"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फ़िंगरप्रिंट सेंसर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"पुष्टि करें"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस की होम स्क्रीन पर जाएं"</string>
@@ -1128,12 +1128,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ज़्यादा जानें"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"ज़्यादा जानने के लिए <xliff:g id="URL">%s</xliff:g> पर जाएं"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोलें"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ऐप्लिकेशन को सेट अप किया गया है"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet में कम से कम एक कार्ड जोड़ा गया है"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• कैमरा ऐप्लिकेशन इंस्टॉल किया गया है"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ऐप्लिकेशन को सेट अप किया गया है"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• कम से कम एक डिवाइस उपलब्ध है"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"नोट लेने से जुड़ा शॉर्टकट इस्तेमाल करने के लिए, नोट लेने का डिफ़ॉल्ट ऐप्लिकेशन चुनें"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि कम से कम एक कार्ड जोड़ा गया हो"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"क्यूआर कोड स्कैनर को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि कैमरा ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ऐप्लिकेशन को शॉर्टकट के तौर पर जोड़ने के लिए, पक्का करें कि ऐप्लिकेशन इंस्टॉल किया गया हो"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• कम से कम एक डिवाइस उपलब्ध है"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"नोट लेने से जुड़ा शॉर्टकट इस्तेमाल करने के लिए, नोट लेने का डिफ़ॉल्ट ऐप्लिकेशन चुनें"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ऐप्लिकेशन चुनें"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"शॉर्टकट को दबाकर रखें"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"रद्द करें"</string>
@@ -1162,4 +1162,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राथमिकता मोड चालू है"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant आपकी बातें सुन रही है"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
+ <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e9fedc4..e921679 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -142,12 +142,11 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je autentificirano"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi za dovršetak"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Otključano licem"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano pomoću lica. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste nastavili."</string>
- <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentičnost provjerena"</string>
+ <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikacija izvršena"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite uzorak"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Koristite zaporku"</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Spremanje nije uspjelo. Pokušajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Spremanje nije uspjelo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Upotrijebite barem četiri znaka"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Upotrijebite manje od ovoliko znakova: <xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -1048,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nema nijednog alarma"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor otiska prsta"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentificirali"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pristupili uređaju"</string>
@@ -1127,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saznajte više"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saznajte više na <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikacija je postavljena"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Najmanje jedna kartica dodana je u Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Instalirajte aplikaciju fotoaparata"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikacija je postavljena"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Dostupan je najmanje jedan uređaj"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Odaberite zadanu aplikaciju za bilješke da biste koristili prečac za pisanje bilježaka"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Za dodavanje aplikacije Wallet kao prečaca provjerite je li instalirana"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Provjerite je li dodana barem jedna kartica kako biste dodali aplikaciju Wallet kao prečac"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Provjerite je li instalirana aplikacija kamere kako biste dodali čitač QR koda kao prečac"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Provjerite je li aplikacija Home instalirana kako biste je dodali kao prečac"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Dostupan je najmanje jedan uređaj"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Odaberite zadanu aplikaciju za bilješke da biste koristili prečac za pisanje bilježaka"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Odaberite aplikaciju"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Prečac za dodirnuti i zadržati"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Odustani"</string>
@@ -1161,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Uključen je prioritetni način rada"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Pažnja Asistenta je aktivirana"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 002d8d7..b0050cf 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Arc hitelesítve"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Megerősítve"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Koppintson a Megerősítés lehetőségre"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Zárolás arccal feloldva"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Zárolás arccal feloldva. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Arc felismerve. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Arc felismerve. A folytatáshoz koppintson a Feloldásra."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hang"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Bevitel"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hallókészülék"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Bekapcsolás…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"A mentés nem sikerült. Próbálja újra."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"A mentés nem sikerült."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Legalább négy karaktert használjon"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Legfeljebb <xliff:g id="LENGTH">%1$d</xliff:g> karaktert használhat"</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>
<string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Koppintással további információkat érhet el."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nincs ébresztés"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Ujjlenyomat-érzékelő"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"a hitelesítéshez"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"eszköz megadásához"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"További információ"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"További információ: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> megnyitása"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Az alkalmazás be van állítva"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Legalább egy kártya hozzá lett adva a Wallethez"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kameraalkalmazás telepítése"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Az alkalmazás be van állítva"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Legalább egy eszköz rendelkezésre áll"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Válassza ki az alapértelmezett jegyzetkészítő alkalmazást, amelyet a jegyzetelési gyorsparancshoz szeretne használni"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ha szeretné felvenni Wallet alkalmazást gyorsparancsként, gondoskodjon az app telepítéséről"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ha szeretné felvenni Wallet alkalmazást gyorsparancsként, győződjön meg róla, hogy hozzáadott legalább egy kártyát a szolgáltatáshoz"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ha szeretné felvenni a QR-kód-szkennelőt gyorsparancsként, győződjön meg róla, hogy van az eszközre telepítve kameraalkalmazás"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ha szeretné felvenni Home appot gyorsparancsként, gondoskodjon az alkalmazás telepítéséről"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Legalább egy eszköz rendelkezésre áll"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Válassza ki az alapértelmezett jegyzetkészítő alkalmazást, amelyet a jegyzetelési gyorsparancshoz szeretne használni"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Alkalmazás kiválasztása"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Tartsa nyomva a parancsikont"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Mégse"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritás mód bekapcsolva"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"A Segéd figyel"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
+ <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f82e930..59ec076 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Դեմքը ճանաչվեց"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Հաստատվեց"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ավարտելու համար հպեք «Հաստատել»"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Ապակողպվեց դեմքով"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ապակողպվել է դեմքով։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Դեմքը ճանաչվեց։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Դեմքը ճանաչվեց։ Սեղմեք ապակողպման պատկերակը։"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Աուդիո"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ականջակալ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Մուտքագրում"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Լսողական սարք"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Միացում…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
@@ -362,7 +360,7 @@
<string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Դեմքը ճանաչվեց"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Սահեցրեք վերև՝ նորից փորձելու համար"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
- <string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
+ <string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր ընկերությանը"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպությանը"</string>
<string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Այս սարքը տրամադրվել է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպության կողմից"</string>
<string name="phone_hint" msgid="6682125338461375925">"Սահահարվածեք հեռախոսի պատկերակից"</string>
@@ -433,11 +431,11 @@
<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_financed_disclosure_named_management" msgid="2307703784594859524">"Այս սարքը տրամադրվել է <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> կազմակերպության կողմից"</string>
- <string name="quick_settings_disclosure_management_named_vpn" msgid="4137564460025113168">"Այս սարքը պատկանում է ձեր կազմակերպությանը և համացանցին միացած է <xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
+ <string name="quick_settings_disclosure_management_named_vpn" msgid="4137564460025113168">"Այս սարքը պատկանում է ձեր ընկերությանը և համացանցին միացած է <xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
<string name="quick_settings_disclosure_named_management_named_vpn" msgid="2169227918166358741">"Այս սարքը պատկանում է <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> կազմակերպությանը և համացանցին միացած է <xliff:g id="VPN_APP">%2$s</xliff:g>-ի միջոցով"</string>
- <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
+ <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"Այս սարքը պատկանում է ձեր ընկերությանը"</string>
<string name="quick_settings_disclosure_named_management" msgid="3476472755775165827">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>» կազմակերպությանը"</string>
- <string name="quick_settings_disclosure_management_vpns" msgid="929181757984262902">"Այս սարքը պատկանում է ձեր կազմակերպությանը և համացանցին միացած է VPN-ների միջոցով"</string>
+ <string name="quick_settings_disclosure_management_vpns" msgid="929181757984262902">"Այս սարքը պատկանում է ձեր ընկերությանը և համացանցին միացած է VPN-ների միջոցով"</string>
<string name="quick_settings_disclosure_named_management_vpns" msgid="3312645578322079185">"Այս սարքը պատկանում է <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> կազմակերպությանը և համացանցին միացած է VPN-ների միջոցով"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Ձեր կազմակերպությունը կարող է վերահսկել ձեր աշխատանքային պրոֆիլի ցանցային թրաֆիկը"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> կազմակերպությունը կարող է վերահսկել ձեր աշխատանքային պրոֆիլի ցանցային թրաֆիկը"</string>
@@ -456,7 +454,7 @@
<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_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> կազմակերպությունը կարող է ստանալ այս սարքի հետ կապված տվյալների օգտագործման թույլտվություն, փոփոխել դրա կարգավորումներն ու կառավարել հավելվածները։\n\nԱվելին իմանալու համար դիմեք <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g> ընկերությանը։"</string>
- <string name="monitoring_description_management" msgid="4308879039175729014">"Այս սարքը պատկանում է ձեր կազմակերպությանը։\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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Ձեր կազմակերպությունը ձեր աշխատանքային պրոֆիլում տեղադրել է վկայագրման կենտրոն։ Ձեր ցանցի ապահով թրաֆիկը կարող է վերահսկվել կամ փոփոխվել։"</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Այս սարքում տեղադրված է վկայագրման կենտրոն։ Ձեր ցանցի ապահով թրաֆիկը կարող է վերահսկվել կամ փոփոխվել։"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Չհաջողվեց պահել։ Նորից փորձեք։"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Չհաջողվեց պահել։"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Օգտագործեք առնվազն 4 նիշ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Օգտագործեք մինչև <xliff:g id="LENGTH">%1$d</xliff:g> նիշ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
<string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Զարթուցիչ դրված չէ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Մատնահետքի սկաներ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"նույնականացնել"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"նշել սարքը"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Իմանալ ավելին"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Իմացեք ավելին <xliff:g id="URL">%s</xliff:g> էջում"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Բացել <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Հավելվածը կարգավորված է"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Առնվազն մեկ քարտ ավելացված է Wallet-ում"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• «Տեսախցիկ» հավելվածը տեղադրված է"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Հավելվածը կարգավորված է"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Հասանելի է առնվազն մեկ սարք"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Ընտրեք նշումների կանխադրված հավելված՝ նշումների ստեղծման դյուրանցումն օգտագործելու համար"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Ընտրել հավելված"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Հպեք դյուրանցմանը և պահեք"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Չեղարկել"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Առաջնահերթության ռեժիմը միացված է"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Օգնականը լսում է"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
+ <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cf3a21e..7b3feaa 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah diautentikasi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Dikonfirmasi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketuk Konfirmasi untuk menyelesaikan"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Kunci dibuka dengan wajah"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Kunci dibuka dengan wajah. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dikenali. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dikenali. Tekan ikon buka kunci untuk melanjutkan."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu dengar"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Mengaktifkan…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat menyimpan. Coba lagi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat menyimpan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gunakan minimal 4 karakter"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gunakan kurang dari <xliff:g id="LENGTH">%1$d</xliff:g> karakter"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
<string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi error saat membaca indikator baterai"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm tidak disetel"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor sidik jari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentikasi"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"masukkan perangkat"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Pelajari lebih lanjut"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Pelajari lebih lanjut di <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikasi disiapkan"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Minimal satu kartu telah ditambahkan ke Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Menginstal aplikasi kamera"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikasi disiapkan"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Tersedia minimal satu perangkat"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Pilih aplikasi catatan default untuk menggunakan pintasan pembuatan catatan"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Pilih aplikasi"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Sentuh lama pintasan"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Batal"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode prioritas diaktifkan"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asisten sedang memerhatikan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 03a52c8..7883207 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Andlit staðfest"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Staðfest"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ýttu á „Staðfesta“ til að ljúka"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Opnað með andliti"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Opnað með andliti. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Andlitið var greint. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Andlitið var greint. Ýttu á opnunartáknið til að halda áfr."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hljóð"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Höfuðtól"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Inntak"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Heyrnartæki"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Kveikir…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ekki hægt að vista. Reyndu aftur."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ekki hægt að vista."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Notaðu að minnsta kosti 4 stafi"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Notaðu færri en <xliff:g id="LENGTH">%1$d</xliff:g> stafi"</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>
<string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ýttu til að fá frekari upplýsingar"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Enginn vekjari"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingrafaralesari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"auðkenna"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"opna tæki"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Nánar"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Nánar á <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Opna <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Forritið er uppsett"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Að minnsta kosti einu korti var bætt við Veski"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Setja upp myndavélarforrit"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Forritið er uppsett"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Að minnsta kosti eitt tæki er tiltækt"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Veldu sjálfgefið glósuforrit til að nota flýtileið fyrir glósugerð"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Velja forrit"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Haltu flýtilyklinum inni"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Hætta við"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Kveikt er á forgangsstillingu"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Hjálparinn er að hlusta"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
+ <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0bab880..fef0fe5 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Volto autenticato"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confermato"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tocca Conferma per completare"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Sbloccato con il volto"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Sbloccato con il volto. Premi per continuare."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Volto riconosciuto. Premi per continuare."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Volto riconosciuto. Premi l\'icona Sblocca e continua."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auricolare"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingresso"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Apparecchi acustici"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Attivazione…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
@@ -308,7 +306,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
- <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Registrazione schermo"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Registrazione dello schermo"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inizia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Interrompi"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossibile salvare. Riprova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossibile salvare."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa almeno 4 caratteri"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Usa meno di <xliff:g id="LENGTH">%1$d</xliff:g> caratteri"</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>
<string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensore di impronte digitali"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"effettuare l\'autenticazione"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"accedere al dispositivo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Scopri di più"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Scopri di più all\'indirizzo <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Apri <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• L\'app sia configurata"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Sia stata aggiunta almeno una carta a Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Sia installata un\'app fotocamera"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• L\'app sia configurata"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ci sia almeno un dispositivo disponibile"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Seleziona un\'app per le note predefinita per usare la scorciatoia per l\'aggiunta di note"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Per aggiungere l\'app Wallet come scorciatoia, assicurati che l\'app sia installata"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Per aggiungere l\'app Wallet come scorciatoia, assicurati che sia stata aggiunta almeno una carta"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Per aggiungere lo scanner di codici QR come scorciatoia, assicurati che ci sia un\'app fotocamera installata"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Per aggiungere l\'app Home come scorciatoia, assicurati che l\'app sia installata"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Ci sia almeno un dispositivo disponibile"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Seleziona un\'app per le note predefinita per usare la scorciatoia per l\'aggiunta di note"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Seleziona app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Tocca scorciatoia/tieni premuto"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annulla"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modalità priorità attivata"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'assistente è attivo"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installa app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 45113e4..255c1da 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"זיהוי הפנים בוצע"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"הנעילה בוטלה באמצעות זיהוי הפנים"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"הנעילה בוטלה באמצעות זיהוי הפנים. יש ללחוץ כדי להמשיך."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"הפנים זוהו. יש ללחוץ כדי להמשיך."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"הפנים זוהו. להמשך יש ללחוץ על סמל ביטול הנעילה."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"אודיו"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"אוזניות"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"קלט"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"מכשירי שמיעה"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ההפעלה מתבצעת…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"סיבוב אוטומטי"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"סיבוב אוטומטי של המסך"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"לא ניתן לשמור. כדאי לנסות שוב."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"לא ניתן לשמור."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"יש להזין 4 תווים לפחות"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"אפשר להזין עד <xliff:g id="LENGTH">%1$d</xliff:g> תווים"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"מספר ה-Build הועתק ללוח."</string>
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"חיישן טביעות אצבע"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"הזנת מכשיר"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"מידע נוסף"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"מידע נוסף זמין בכתובת <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"פתיחת <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• האפליקציה מוגדרת"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• לפחות כרטיס אחד נוסף ל-Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• התקנה של אפליקציית מצלמה"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• האפליקציה מוגדרת"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• יש לפחות מכשיר אחד זמין"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"צריך לבחור אפליקציית פתקים שתיפתח כברירת מחדל כשייעשה שימוש במקש הקיצור לכתיבת פתקים"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"כדי להוסיף את אפליקציית Wallet כקיצור דרך, צריך לוודא שהאפליקציה מותקנת"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"כדי להוסיף את אפליקציית Wallet כקיצור דרך, צריך לוודא שנוסף לפחות כרטיס אחד"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"כדי להוסיף את סורק קודי ה-QR כקיצור דרך, צריך לוודא שמותקנת אפליקציית מצלמה"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"כדי להוסיף את אפליקציית Home כקיצור דרך, צריך לוודא שהאפליקציה מותקנת"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• יש לפחות מכשיר אחד זמין"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"צריך לבחור אפליקציית פתקים שתיפתח כברירת מחדל כשייעשה שימוש במקש הקיצור לכתיבת פתקים"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"בחירת אפליקציה"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"מקש קיצור ללחיצה ארוכה"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ביטול"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"מצב \'עדיפות\' מופעל"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant מאזינה"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
+ <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e39c979..d74d2f1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"顔を認証しました"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認しました"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"完了するには [確認] をタップしてください"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"顔でロック解除しました"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"顔でロック解除しました。押して続行してください。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"顔を認識しました。押して続行してください。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"顔を認識しました。ロック解除アイコンを押して続行します。"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"オーディオ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ヘッドセット"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"入力"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"補聴器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ON にしています…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"保存できません。もう一度お試しください。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"保存できません。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"4 文字以上にしてください"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"使用できる文字数は <xliff:g id="LENGTH">%1$d</xliff:g> 文字未満です"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
<string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"バッテリー残量の読み込み中に問題が発生しました"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"画面ロックを設定"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋認証センサー"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"認証"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"デバイスを入力"</string>
@@ -1111,10 +1109,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"アシスタントが音声認識中です"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 件の通知}other{# 件の通知}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>、<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"メモ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"メモ、<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ブロードキャスト"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> のブロードキャストを停止しますか?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャストしたり、出力を変更したりすると、現在のブロードキャストが停止します。"</string>
@@ -1130,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"詳細"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"詳しくは、<xliff:g id="URL">%s</xliff:g> をご覧ください"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> を開く"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• アプリが設定されている"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ウォーレットに追加されているカードが 1 枚以上ある"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• カメラアプリをインストールする"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• アプリが設定されている"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• 利用できるデバイスが 1 台以上ある"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"メモのショートカットを使用するデフォルトのメモアプリを選択してください"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ウォレット アプリをショートカットとして追加するには、アプリがインストールされていることを確認してください"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ウォレット アプリをショートカットとして追加するには、カードが 1 枚以上追加されていることを確認してください"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR コードスキャナをショートカットとして追加するには、カメラアプリがインストールされていることを確認してください"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Google Home アプリをショートカットとして追加するには、アプリがインストールされていることを確認してください"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 利用できるデバイスが 1 台以上ある"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"メモのショートカットを使用するデフォルトのメモアプリを選択してください"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"アプリを選択"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ショートカットの長押しが必要です"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"キャンセル"</string>
@@ -1164,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先モードは ON です"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"アシスタントは起動済みです"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
+ <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index de5a393..053989e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"სახის ამოცნობილია"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"დადასტურებული"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"დასასრულებლად შეეხეთ „დადასტურებას“"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"განიბლოკა სახით"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"განიბლოკა სახით. დააჭირეთ გასაგრძელებლად."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ამოცნობილია სახით. დააჭირეთ გასაგრძელებლად."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ამოცნობილია სახით. გასაგრძელებლად დააჭირეთ განბლოკვის ხატულას."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"აუდიო"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ყურსაცვამი"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"შეყვანა"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"სმენის მოწყობილობები"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ირთვება…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"შენახვა ვერ ხერხდება. ცადეთ ხელახლა."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"შენახვა ვერ ხერხდება."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"გამოიყენეთ მინიმუმ 4 სიმბოლო."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"გამოიყენეთ <xliff:g id="LENGTH">%1$d</xliff:g>-ზე ნაკლები სიმბოლო"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
<string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"თქვენი ბატარეის მზომის წაკითხვასთან დაკავშირებით პრობლემა დაფიქსირდა"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"შეეხეთ მეტი ინფორმაციისთვის"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"მაღვიძარა არ არის"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"თითის ანაბეჭდის სენსორი"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ავტორიზაცია"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"მოწყობილობის შეყვანა"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"შეიტყვეთ მეტი"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"შეიტყვეთ მეტი აქ: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> აპის გახსნა"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• აპი დაყენებულია"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• საფულეში დამატებულია მინიმუმ ერთი ბარათი"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• დააინსტალირეთ კამერის აპი"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• აპი დაყენებულია"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ხელმისაწვდომია მინიმუმ ერთი მოწყობილობა"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"აირჩიეთ ნაგულისხმევი ჩანიშვნების აპი, რათა ჩანიშვნების შექმნის მალსახმობი გამოიყენოთ"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"საფულის აპის მალსახმობის დასამატებლად დარწმუნდით, რომ აპი დაინსტალირებულია"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"საფულის აპის მალსახმობის დასამატებლად დარწმუნდით, რომ დამატებულია მინიმუმ ერთი ბარათი"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR კოდის სკანერის მალსახმობის დასამატებლად დარწმუნდით, რომ დაინსტალირებულია კამერის აპი"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"მთავარი აპის მალსახმობის დასამატებლად დარწმუნდით, რომ აპი დაინსტალირებულია"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ხელმისაწვდომია მინიმუმ ერთი მოწყობილობა"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"აირჩიეთ ჩანიშვნების ნაგულისხმევი აპი, რათა ჩანიშვნების შექმნის მალსახმობი გამოიყენოთ"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"აირჩიეთ აპი"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"შეხების დაamp; მოცდის მალსახმობი"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"გაუქმება"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"პრიორიტეტული რეჟიმი ჩართულია"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"ასისტენტის ყურადღების ფუნქცია ჩართულია"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
+ <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 5187026..ef1a4d3 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Бет танылды."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Расталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Аяқтау үшін \"Растау\" түймесін түртіңіз."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Бетпен ашылды."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Бетпен ашылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Бет танылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Бет танылды. Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Aудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Кіріс"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Есту аппараттары"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылуда…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сақталмайды. Қайталап көріңіз."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сақталмайды."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Кемінде 4 таңба пайдаланыңыз."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Ең көбі <xliff:g id="LENGTH">%1$d</xliff:g> таңба пайдаланыңыз."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
<string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Оятқыш орнатылмаған."</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Саусақ ізін оқу сканері"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аутентификациялау"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"құрылғыны енгізу"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Толық ақпарат"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Толық ақпарат: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ашу"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Қолданба реттелген"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet-ке кемінде бір карта қосылған"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Камера қолданбасын орнатыңыз"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Қолданба реттелген"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Кемінде бір құрылғы қолжетімді"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Жазба жазу таңбашасын пайдалану үшін әдепкі жазба қолданбаны таңдаңыз."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Қолданба таңдау"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Таңбашаны басып тұрыңыз."</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Бас тарту"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\"Маңызды\" режимі қосулы."</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant қосулы."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
+ <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index ea6ae29..150546c 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"បានផ្ទៀងផ្ទាត់មុខ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"បានបញ្ជាក់"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ចុច \"បញ្ជាក់\" ដើម្បីបញ្ចប់"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"បានដោះសោដោយប្រើមុខ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបន្ត។"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"សំឡេង"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"កាស"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"បញ្ចូល"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"កំពុងបើក..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិលស្វ័យប្រវត្តិ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"មិនអាចរក្សាទុកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"មិនអាចរក្សាទុកបានទេ។"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ប្រើយ៉ាងហោចណាស់ 4 តួអក្សរ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ប្រើតិចជាង <xliff:g id="LENGTH">%1$d</xliff:g> តួអក្សរ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខកំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខកំណែបង្កើតទៅឃ្លីបបត។"</string>
<string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុងការអានឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"មិនបានកំណត់ម៉ោងរោទ៍ទេ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ផ្ទៀងផ្ទាត់"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"បញ្ចូលឧបករណ៍"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ស្វែងយល់បន្ថែម"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"ស្វែងយល់បន្ថែមតាមរយៈ <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"បើក <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• កម្មវិធីត្រូវបានរៀបចំ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• កាតយ៉ាងតិចមួយត្រូវបានបញ្ចូលទៅក្នុង Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ដំឡើងកម្មវិធីកាមេរ៉ា"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• កម្មវិធីត្រូវបានរៀបចំ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ឧបករណ៍យ៉ាងតិចមួយអាចប្រើបាន"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"ជ្រើសរើសកម្មវិធីកំណត់ចំណាំលំនាំដើម ដើម្បីប្រើផ្លូវកាត់សម្រាប់ការកត់ចំណាំ"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"ដើម្បីបញ្ចូលកម្មវិធី Wallet ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីត្រូវបានដំឡើង"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"ដើម្បីបញ្ចូលកម្មវិធី Wallet ជាផ្លូវកាត់ សូមប្រាកដថាបានបញ្ចូលកាតយ៉ាងហោចណាស់មួយ"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"ដើម្បីបញ្ចូលកម្មវិធីស្កេនកូដ QR ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីកាមេរ៉ាត្រូវបានដំឡើង"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"ដើម្បីបញ្ចូលកម្មវិធី Home ជាផ្លូវកាត់ សូមប្រាកដថាកម្មវិធីត្រូវបានដំឡើង"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ឧបករណ៍យ៉ាងតិចមួយអាចប្រើបាន"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"ជ្រើសរើសកម្មវិធីកំណត់ចំណាំលំនាំដើម ដើម្បីប្រើផ្លូវកាត់សម្រាប់ការកត់ចំណាំ"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ជ្រើសរើសកម្មវិធី"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ចុចឱ្យជាប់លើផ្លូវកាត់"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"បោះបង់"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"មុខងារអាទិភាពត្រូវបានបើក"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"ភាពប្រុងប្រៀបរបស់ Google Assistant ត្រូវបានបើក"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
+ <string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4155ead..96e955e 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ಪೂರ್ಣಗೊಳಿಸಲು ದೃಢೀಕರಿಸಿ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ಮುಖದ ಮೂಲಕ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಅನ್ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ಆಡಿಯೋ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ಹೆಡ್ಸೆಟ್"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ಇನ್ಪುಟ್"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ಕನಿಷ್ಠ 4 ಅಕ್ಷರಗಳನ್ನು ಬಳಸಿ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ ಅಕ್ಷರಗಳನ್ನು ಬಳಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್ಬೋರ್ಡ್ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
<string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ಅಲಾರಾಂ ಸೆಟ್ ಆಗಿಲ್ಲ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ದೃಢೀಕರಿಸಿ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> ನಲ್ಲಿ ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ಆ್ಯಪ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಲಾಗಿದೆ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ವಾಲೆಟ್ಗೆ ಕನಿಷ್ಠ ಒಂದು ಕಾರ್ಡ್ ಅನ್ನು ಸೇರಿಸಲಾಗಿದೆ"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ಕ್ಯಾಮರಾ ಆ್ಯಪ್ ಒಂದನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ಆ್ಯಪ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಲಾಗಿದೆ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ಕನಿಷ್ಠ ಒಂದು ಸಾಧನ ಲಭ್ಯವಿದೆ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"ನೋಟ್ಸ್ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಬಳಸಲು ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ಸ್ಪರ್ಶಿಸಿ ಹೋಲ್ಡ್ ಮಾಡಿ ಶಾರ್ಟ್ಕಟ್"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ರದ್ದುಗೊಳಿಸಿ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ಆದ್ಯತೆಯ ಮೋಡ್ ಆನ್ ಆಗಿದೆ"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ನಿಮ್ಮ ಮಾತನ್ನು ಆಲಿಸುತ್ತಿದೆ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
+ <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e5092b4..2a82ddc 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"얼굴이 인증되었습니다."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"확인함"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"완료하려면 확인을 탭하세요."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"얼굴 인식으로 잠금 해제되었습니다."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"얼굴이 인식되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"얼굴이 인식되었습니다. 계속하려면 아이콘을 누르세요."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"오디오"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"헤드셋"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"입력"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"보청기"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"켜는 중..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"저장할 수 없습니다. 다시 시도해 주세요."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"저장할 수 없습니다."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"4자 이상 입력하세요."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>자 미만이어야 합니다."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
<string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"설정된 알람 없음"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"지문 센서"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"인증"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"기기 입력"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"자세히 알아보기"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>에서 자세히 알아보세요."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> 열기"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• 앱이 설정되어 있습니다."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• 1개 이상의 카드가 월렛에 추가되어 있습니다."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• 카메라 앱이 설치되어 있습니다."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• 앱이 설정되어 있습니다."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• 1대 이상의 기기를 사용할 수 있습니다."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"메모 바로가기를 사용하려면 기본 메모 앱을 선택합니다."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"앱 선택"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"바로가기를 길게 터치하세요."</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"취소"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"우선순위 모드 설정됨"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"어시스턴트가 대기 중임"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
+ <string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 12a7439b..6ceb1e7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Жүздүн аныктыгы текшерилди"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ырасталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Бүтүрүү үчүн \"Ырастоо\" баскычын басыңыз"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Түзмөгүңүздү жүзүңүз менен ачтыңыз"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Кулпуну жүзүңүз менен ачтыңыз. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Жүз таанылды. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Жүз таанылды. Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Киргизүү"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Угуу аппараттары"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Күйгүзүлүүдө…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сакталган жок. Кайталап көрүңүз."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сакталган жок."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Кеминде 4 символдон турушу керек"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> символдон ашпашы керек"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
<string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ойготкуч коюлган жок"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Манжа изинин сенсору"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"аныктыгын текшерүү"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"түзмөккө кирүү"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Кеңири маалымат"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Кеңири маалымат: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ачуу"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Колдонмо туураланды"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Капчыкка кеминде бир карта кошулду"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Камера колдонмосун орнотуу"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Колдонмо туураланды"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Кеминде бир түзмөк жеткиликтүү"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Эскертме жазуу ыкчам баскычын колдонуу үчүн демейки эскертме жазуу колдонмосун тандаңыз"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Колдонмо тандоо"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Ыкчам баскычты басып туруңуз"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Токтотуу"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Маанилүү сүйлөшүүлөр режими күйүк"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Жардамчы иштетилди"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
+ <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index f277e8a..da4547b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -76,4 +76,10 @@
<!-- Bouncer user switcher margins -->
<dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
<dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
+
+ <!-- Power Menu Lite -->
+ <!-- These values are for small screen landscape. For larger landscape screens, they are
+ overlaid -->
+ <dimen name="global_actions_button_size">72dp</dimen>
+ <dimen name="global_actions_button_padding">26dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7e81735..deec7d0 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ຢືນຢັນແລ້ວ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ແຕະຢືນຢັນເພື່ອສຳເລັດ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ປົດລັອກດ້ວຍໃບໜ້າແລ້ວ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ສຽງ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ຊຸດຫູຟັງ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ການປ້ອນຂໍ້ມູນ"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ເຄື່ອງຊ່ວຍຟັງ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ກຳລັງເປີດ..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນອັດຕະໂນມັດ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ບໍ່ສາມາດບັນທຶກໄດ້. ກະລຸນາລອງໃໝ່."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ບໍ່ສາມາດບັນທຶກໄດ້."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ໃຊ້ຢ່າງໜ້ອຍ 4 ຕົວອັກສອນ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ໃຊ້ໜ້ອຍກວ່າ <xliff:g id="LENGTH">%1$d</xliff:g> ຕົວອັກສອນ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
<string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ເກີດບັນຫາໃນການອ່ານຕົວວັດແທກແບັດເຕີຣີຂອງທ່ານ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ບໍ່ໄດ້ຕັ້ງໂມງປຸກ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ເຊັນເຊີລາຍນິ້ວມື"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ພິສູດຢືນຢັນ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ເຂົ້າອຸປະກອນ"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ສຶກສາເພີ່ມເຕີມ"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"ສຶກສາເພີ່ມເຕີມຢູ່ <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"ເປີດ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ແອັບໄດ້ຮັບການຕັ້ງຄ່າແລ້ວ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ມີການເພີ່ມຢ່າງໜ້ອຍ 1 ບັດໃສ່ໃນ Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ຕິດຕັ້ງແອັບກ້ອງຖ່າຍຮູບ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ແອັບໄດ້ຮັບການຕັ້ງຄ່າແລ້ວ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ມີຢ່າງໜ້ອຍ 1 ອຸປະກອນພ້ອມໃຫ້ນຳໃຊ້"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"ເລືອກແອັບບັນທຶກເລີ່ມຕົ້ນເພື່ອໃຊ້ທາງລັດການຈົດບັນທຶກ"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ເລືອກແອັບ"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ແຕະທາງລັດຄ້າງໄວ້"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ຍົກເລີກ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ໂໝດຄວາມສຳຄັນເປີດຢູ່"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"ການເອີ້ນໃຊ້ຜູ້ຊ່ວຍເປີດຢູ່"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
+ <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 87ba40f..44f7b68 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Veidas autentifikuotas"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Patvirtinta"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Paliesk. „Patvirtinti“, kad užbaigtumėte"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Atrakinta pagal veidą"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Veidas atpažintas. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Veidas atpažintas. Tęskite paspaudę atrakinimo piktogramą."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Virtualiosios realybės įrenginys"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Įvestis"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Klausos aparatai"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Įjungiama…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nepavyko išsaugoti. Bandykite dar kartą."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nepavyko išsaugoti."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Naudokite bent 4 simbolius"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Naudokite daugiausia <xliff:g id="LENGTH">%1$d</xliff:g> simb."</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>
<string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nuskaitant akumuliatoriaus skaitiklį iškilo problema"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Palieskite, kad sužinotumėte daugiau informacijos"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenustatyta signalų"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Kontrolinio kodo jutiklis"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"nustatytumėte tapatybę"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"pasiektumėte įrenginį"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Sužinokite daugiau"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Sužinokite daugiau adresu <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atidaryti „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Programa nustatyta"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Prie „Wallet“ pridėta bent viena kortelė"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Įdiekite Fotoaparato programą"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Programa nustatyta"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Pasiekiamas bent vienas įrenginys"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Pasirinkite numatytąją užrašų programą, naudotiną su užrašų kūrimo sparčiuoju klavišu"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Pasirinkite programą"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Paliesk. ir palaik. spart. klav."</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Atšaukti"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteto režimas įjungtas"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Padėjėjas klauso"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
+ <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e9f34074..fc227f0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Seja autentificēta"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Apstiprināts"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lai pabeigtu, pieskarieties Apstiprināt"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Ierīce atbloķēta ar seju"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ierīce atbloķēta ar seju. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Seja atpazīta. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Seja atpazīta. Lai turpinātu, nospiediet atbloķēšanas ikonu."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Austiņas"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ievade"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Dzirdes aparāti"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Notiek ieslēgšana…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nevar saglabāt. Mēģiniet vēlreiz."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nevar saglabāt."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Izmantojiet vismaz 4 rakstzīmes"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Izmantojiet mazāk nekā <xliff:g id="LENGTH">%1$d</xliff:g> rakstzīmes."</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>
<string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nevar iegūt informāciju par akumulatora uzlādes līmeni."</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Pieskarieties, lai iegūtu plašāku informāciju."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nav iestatīts signāls"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Pirksta nospieduma sensors"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"veiktu autentificēšanu"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"izmantotu ierīci"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Uzzināt vairāk"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Uzziniet vairāk vietnē <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atvērt lietotni <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Lietotne ir iestatīta."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Makam ir pievienota vismaz viena karte."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Ir instalēta kameras lietotne."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Lietotne ir iestatīta."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ir pieejama vismaz viena ierīce."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Atlasiet noklusējuma piezīmju lietotni, lai izmantotu piezīmju pierakstīšanas saīsni."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Atlasīt lietotni"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pieskarieties saīsnei un turiet."</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Atcelt"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritātes režīms ir ieslēgts"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistents klausās"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 037fd7b..5dad015 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е проверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Допрете „Потврди“ за да се заврши"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Отклучено со лик"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отклучено со лик. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето е препознаено. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето е препознаено. Притиснете ја иконата за отклучување за да продолжите."</string>
@@ -210,7 +209,7 @@
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
<string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"„Брзи поставки“ и „Панел со известувања“."</string>
- <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
+ <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучен екран."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Работен заклучен екран"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"целосна тишина"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Влез"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни помагала"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Се вклучува…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се зачува. Обидете се повторно."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се зачува."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Употребете најмалку 4 знаци"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Употребете помалку од <xliff:g id="LENGTH">%1$d</xliff:g> знаци"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
<string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем при читањето на мерачот на батеријата"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Допрете за повеќе информации"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Не е поставен аларм"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отпечатоци"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"автентицирате"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"внесете уред"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Дознајте повеќе"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Дознајте повеќе на <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворете ја <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• апликацијата е поставена"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• најмалку една картичка е додадена во Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• инсталирана е апликација за камера"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• апликацијата е поставена"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• достапен е најмалку еден уред"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Изберете стандардна апликација за белешки за да ја користите кратенката за фаќање белешки"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Изберете апликација"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Допрете и задржете ја кратенката"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Откажи"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетниот режим е вклучен"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Вниманието на „Помошникот“ е вклучено"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
+ <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e8ec2a4..83d045e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"സ്ഥിരീകരിച്ചു"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"പൂർത്തിയാക്കാൻ സ്ഥിരീകരിക്കുക ടാപ്പ് ചെയ്യൂ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്തു"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്തു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ഓഡിയോ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ഹെഡ്സെറ്റ്"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ഇൻപുട്ട്"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ശ്രവണ സഹായികൾ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ഓണാക്കുന്നു…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"സ്ക്രീൻ സ്വയമേവ തിരിയൽ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"സ്ക്രീൻ സ്വയമേവ തിരിക്കുക"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"സംരക്ഷിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"സംരക്ഷിക്കാൻ കഴിയില്ല."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"കുറഞ്ഞത് 4 പ്രതീകങ്ങളെങ്കിലും ഉപയോഗിക്കുക"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>-ൽ കുറവ് പ്രതീകങ്ങൾ ഉപയോഗിക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
<string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്നമുണ്ട്"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"അലാറം സജ്ജീകരിച്ചിട്ടില്ല"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"സ്ക്രീൻ ലോക്ക് നൽകുക"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ഫിംഗർപ്രിന്റ് സെൻസർ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"പരിശോധിച്ചുറപ്പിക്കുക"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ഉപകരണം നൽകുക"</string>
@@ -1128,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"കൂടുതലറിയുക"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> എന്നതിൽ കൂടുതലറിയുക"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> തുറക്കുക"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ആപ്പ് സജ്ജീകരിച്ചിട്ടുണ്ട്"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet-ലേക്ക് ഒരു കാർഡെങ്കിലും ചേർത്തിട്ടുണ്ട്"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ഒരു ക്യാമറാ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ട്"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ആപ്പ് സജ്ജീകരിച്ചിട്ടുണ്ട്"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ഒരു ഉപകരണമെങ്കിലും ലഭ്യമാണ്"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"കുറിപ്പ് രേഖപ്പെടുത്തൽ കുറുക്കുവഴി ഉപയോഗിക്കുന്നതിന് ഒരു ഡിഫോൾട്ട് കുറിപ്പ് ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"കുറുക്കുവഴിയായി Wallet ആപ്പ് ചേർക്കാൻ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"കുറുക്കുവഴിയായി Wallet ആപ്പ് ചേർക്കാൻ, ഒരു കാർഡെങ്കിലും ചേർത്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"കുറുക്കുവഴിയായി QR കോഡ് സ്കാനർ ചേർക്കാൻ, ക്യാമറാ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"കുറുക്കുവഴിയായി Home ആപ്പ് ചേർക്കാൻ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• ഒരു ഉപകരണമെങ്കിലും ലഭ്യമാണ്"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"കുറിപ്പ് രേഖപ്പെടുത്തൽ കുറുക്കുവഴി ഉപയോഗിക്കുന്നതിന് ഒരു ഡിഫോൾട്ട് കുറിപ്പ് ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"സ്പർശിച്ച് പിടിക്കുക കുറുക്കുവഴി"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"റദ്ദാക്കുക"</string>
@@ -1162,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"മുൻഗണനാ മോഡ് ഓണാണ്"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant സജീവമാണ്"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
+ <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 21257ac..5c6bef3 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Царайг баталгаажууллаа"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Баталгаажсан"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Дуусгахын тулд баталгаажуулахыг товших"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Царайгаар түгжээг тайлсан"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Царайг таньсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Царайг таньсан. Үргэлжлүүлэх бол түгжээг тайлах дүрсийг дар."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Чихэвч"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Оролт"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Сонсголын төхөөрөмж"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Асааж байна…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Хадгалах боломжгүй. Дахин оролдоно уу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Хадгалах боломжгүй."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Дор хаяж 4 тэмдэгт ашиглана уу."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>-с цөөн тэмдэгт ашиглана уу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
<string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Сэрүүлэг тавиагүй"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Хурууны хээ мэдрэгч"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"баталгаажуулах"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"төхөөрөмж оруулах"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Нэмэлт мэдээлэл авах"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>-с нэмэлт мэдээлэл авна уу"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>-г нээх"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Аппыг тохируулсан"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Дор хаяж нэг картыг Wallet-д нэмсэн"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Камер аппыг суулгах"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Аппыг тохируулсан"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Дор хаяж нэг төхөөрөмж боломжтой"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Тэмдэглэл хөтлөх товчлолыг ашиглахын тулд тэмдэглэлийн өгөгдмөл аппыг сонгоно уу"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Апп сонгох"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Товчлолд хүрээд удаан дарна уу"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Цуцлах"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Чухал горим асаалттай байна"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Туслах анхаарлаа хандуулж байна"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
+ <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8c7eec4..55198be 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"चेहऱ्याने अनलॉक केले आहे"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडिओ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवणयंत्रे"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सुरू करत आहे…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव्ह करू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव्ह करू शकत नाही."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"किमान चार वर्ण वापरा"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वर्णांपेक्षा कमी वर्ण वापरा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
<string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म सेट केला नाही"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फिंगरप्रिंट सेन्सर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ऑथेंटिकेट करा"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिव्हाइस एंटर करा"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"अधिक जाणून घ्या"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> येथे अधिक जाणून घ्या"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> उघडा"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• अॅप सेट करणे"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet मध्ये किमान एक कार्ड जोडणे"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• कॅमेरा अॅप इंस्टॉल करणे"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• अॅप सेट करणे"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• किमान एक डिव्हाइस उपलब्ध करणे"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"टिपा घेण्याशी संबंधित शॉर्टकट वापरण्याकरिता टिपांसाठीचे डीफॉल्ट अॅप निवडा"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ॲप शॉर्टकट म्हणून जोडण्यासाठी ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ॲप शॉर्टकट म्हणून जोडण्यासाठी किमान एक कार्ड जोडले असल्याची खात्री करा"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR कोड स्कॅनर शॉर्टकट म्हणून जोडण्यासाठी कॅमेरा ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home अॅप शॉर्टकट म्हणून जोडण्यासाठी ॲप इंस्टॉल केले असल्याची खात्री करा"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• किमान एक डिव्हाइस उपलब्ध करणे"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"टिपा घेण्यासंबंधित शॉर्टकट वापरण्याकरिता टिपांसाठीचे डीफॉल्ट अॅप निवडा"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"अॅप निवडा"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"स्पर्श करा आणि धरून ठेवा शॉर्टकट"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"रद्द करा"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राधान्य मोड सुरू आहे"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant चे लक्ष हे आता अॅक्टिव्ह आहे"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string>
+ <string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8eadbb6..100feac 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah disahkan"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Disahkan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketik Sahkan untuk menyelesaikan"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Dibuka kunci dengan wajah"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Dibuka kunci dengan wajah. Tekan untuk meneruskan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dicam. Tekan untuk meneruskan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dicam. Tekan ikon buka kunci untuk meneruskan."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Set Kepala"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu pendengaran"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Menghidupkan…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat disimpan. Cuba lagi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat disimpan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gunakan sekurang-kurangnya 4 aksara"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gunakan kurang daripada <xliff:g id="LENGTH">%1$d</xliff:g> aksara"</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>
<string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Masalah membaca meter bateri anda"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketik untuk mendapatkan maklumat lanjut"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Tiada penggera"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Penderia cap jari"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"sahkan"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"akses peranti"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Ketahui lebih lanjut"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Ketahui lebih lanjut di <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Apl disediakan"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Sekurang-kurangnya satu kad telah ditambahkan pada Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Pasang apl kamera"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Apl disediakan"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Sekurang-kurangnya satu peranti tersedia"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Pilih apl nota lalai untuk menggunakan pintasan pengambilan nota"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Untuk menambahkan apl Wallet sebagai pintasan, pastikan apl telah dipasang"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Untuk menambahkan apl Wallet sebagai pintasan, pastikan sekurang-kurangnya satu kad telah ditambahkan"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Untuk menambahkan pengimbas kod QR sebagai pintasan, pastikan apl kamera telah dipasang"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Untuk menambahkan apl Home sebagai pintasan, pastikan apl telah dipasang"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Sekurang-kurangnya satu peranti tersedia"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pilih apl nota lalai untuk menggunakan pintasan pengambilan nota"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Pilih apl"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pintasan sentuh & tahan"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Batal"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mod keutamaan dihidupkan"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Perhatian pembantu dihidupkan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
+ <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 7fe03b3..34f580a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"အတည်ပြုပြီးပြီ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"အပြီးသတ်ရန်အတွက် \'အတည်ပြုရန်\' ကို တို့ပါ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"မျက်နှာဖြင့် ဖွင့်ထားသည်"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
@@ -414,7 +413,7 @@
<string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"အက်ပ်တစ်ခုဖြင့် မျှဝေ၊ ရုပ်သံဖမ်း (သို့) ကာစ်လုပ်သည့်အခါ Android သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"စတင်ရန်"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"သင်၏ IT စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
- <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ကိရိယာဆိုင်ရာ မူဝါဒက ဖန်သားပြင်ပုံဖမ်းခြင်းကို ပိတ်ထားသည်"</string>
+ <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ကိရိယာ မူဝါဒက ဖန်သားပြင်ပုံဖမ်းခြင်းကို ပိတ်ထားသည်"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးရှင်းရန်"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"သိမ်း၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"သိမ်း၍မရပါ။"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"အနည်းဆုံး အက္ခရာ ၄ လုံး သုံးရန်"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"အက္ခရာ <xliff:g id="LENGTH">%1$d</xliff:g> လုံးအောက် သုံးရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
<string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
@@ -1048,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"နှိုးစက်ပေးမထားပါ"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"ဖန်သားပြင်လော့ခ် ထည့်ရန်"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"လက်ဗွေ အာရုံခံကိရိယာ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"အထောက်အထားစိစစ်ရန်"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"စက်ပစ္စည်းသို့ ဝင်ရန်"</string>
@@ -1127,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ပိုမိုလေ့လာရန်"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> တွင် ပိုမိုလေ့လာရန်"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ဖွင့်ရန်"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• အက်ပ်ကို စနစ်ထည့်သွင်းထားရမည်"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet တွင် အနည်းဆုံးကတ်တစ်ခု ထည့်ထားရမည်"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ကင်မရာအက်ပ် ထည့်သွင်းထားရမည်"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• အက်ပ်ကို စနစ်ထည့်သွင်းထားရမည်"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• အနည်းဆုံး စက်တစ်ခုသုံးနိုင်ရမည်"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"မှတ်စုရေးသည့် ဖြတ်လမ်းလင့်ခ်သုံးရန်အတွက် မူရင်းမှတ်စုများအက်ပ် ရွေးရန်"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ၎င်းအားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် အနည်းဆုံး ကတ်တစ်ခုထည့်ထားကြောင်း သေချာပါစေ"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR ကုဒ် စကင်ဖတ်စနစ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ကင်မရာအက်ပ်အားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home အက်ပ်ကို ဖြတ်လမ်းလင့်ခ်အဖြစ်ထည့်ရန် ၎င်းအားထည့်သွင်းထားကြောင်း သေချာပါစေ"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• အနည်းဆုံး စက်တစ်ခုသုံးနိုင်ရမည်"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"မှတ်စုရေးသည့် ဖြတ်လမ်းလင့်ခ်သုံးရန်အတွက် မူရင်းမှတ်စုများအက်ပ် ရွေးရန်"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"အက်ပ်ရွေးရန်"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ဖြတ်လမ်းလင့်ခ်ကို ထိပြီးဖိထားပါ"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"မလုပ်တော့"</string>
@@ -1161,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ဦးစားပေးမုဒ် ဖွင့်ထားသည်"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant နားထောင်နေသည်"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
+ <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 369f6af..d516e50 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet er autentisert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekreftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trykk på Bekreft for å fullføre"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Låst opp med ansiktet"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst opp med ansiktet. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet er gjenkjent. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Hodetelefoner"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Innenhet"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Slår på …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan ikke lagre. Prøv på nytt."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan ikke lagre."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Bruk minst 4 tegn"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Bruk færre enn <xliff:g id="LENGTH">%1$d</xliff:g> tegn"</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>
<string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trykk for å få mer informasjon"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm angitt"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeravtrykkssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentiser"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"åpne enheten"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Finn ut mer"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Finn ut mer på <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åpne <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• appen er konfigurert"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• minst ett kort er lagt til i Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• en kameraapp er installert"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• appen er konfigurert"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• minst én enhet er tilgjengelig"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Velg en standard notatapp du vil bruke med notatsnarveien"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Velg app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Trykk på og hold inne snarveien"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Avbryt"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteringsmodus er på"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistentoppmerksomhet er på"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 69ee5eb..70d3d5b 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"अनुहार प्रमाणीकरण गरियो"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि भयो"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूरा गर्नका लागि पुष्टि गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"अनुहार प्रयोग गरी अनलक गरियो"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न थिच्नुहोस्।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"अनुहार पहिचान गरियो। जारी राख्न थिच्नुहोस्।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"अनुहार पहिचान गरियो। जारी राख्न अनलक आइकनमा थिच्नुहोस्।"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"अडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवण यन्त्रहरू"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सक्रिय गर्दै…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
@@ -464,8 +462,8 @@
<string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"तपाईंका एड्मिनले \'नेटवर्क लगिङ\' सुविधा अन गर्नुभएको छ। यो सुविधाले तपाईंको कार्य प्रोफाइलको ट्राफिक अनुगमन गर्छ तर व्यक्तिगत प्रोफाइलको ट्राफिक भने अनुगमन गर्दैन।"</string>
<string name="monitoring_description_named_vpn" msgid="8220190039787149671">"यो डिभाइस <xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएको छ। तपाईंको VPN प्रदायकले इमेल र ब्राउजिङ डेटालगायतका नेटवर्कसम्बन्धी गतिविधि हेर्न सक्छ।"</string>
<string name="monitoring_description_managed_device_named_vpn" msgid="7693648349547785255">"यो डिभाइस <xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएको छ। तपाईंका IT एड्मिन इमेल र ब्राउजिङ डेटालगायतका नेटवर्कसम्बन्धी गतिविधि हेर्न सक्नुहुन्छ।"</string>
- <string name="monitoring_description_two_named_vpns" msgid="6726394451199620634">"तपाईंको डिभाइस <xliff:g id="VPN_APP_0">%1$s</xliff:g> र <xliff:g id="VPN_APP_1">%2$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएको छ। तपाईंको सूचना प्रविधि व्यवस्थापक तपाईंको इमेल र ब्राउजिङ डेटासहित नेटवर्कसम्बन्धी क्रियाकलाप हेर्न सक्छन्।"</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"तपाईंका कामसम्बन्धी एपहरू <xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएका छन्। तपाईंको सूचना प्रविधि व्यवस्थापक र VPN प्रदायक कामसम्बन्धी एपहरूमा भएका तपाईंका इमेल र ब्राउजिङ डेटासहित नेटवर्कसम्बन्धी क्रियाकलाप हेर्न सक्छन्।"</string>
+ <string name="monitoring_description_two_named_vpns" msgid="6726394451199620634">"तपाईंको डिभाइस <xliff:g id="VPN_APP_0">%1$s</xliff:g> र <xliff:g id="VPN_APP_1">%2$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएको छ। तपाईंका IT एड्मिन तपाईंका इमेल र ब्राउजिङ डेटासहित नेटवर्कसम्बन्धी क्रियाकलाप हेर्न सक्छन्।"</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"तपाईंका कामसम्बन्धी एपहरू <xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएका छन्। तपाईंको IT एड्मिन र VPN प्रदायक कामसम्बन्धी एपहरूमा भएका तपाईंका इमेल र ब्राउजिङ डेटासहित नेटवर्कसम्बन्धी क्रियाकलाप हेर्न सक्छन्।"</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"तपाईंका व्यक्तिगत एपहरू <xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत इन्टरनेटमा कनेक्ट गरिएका छन्। तपाईंको VPN प्रदायक तपाईंको इमेल र ब्राउजिङ डेटासहित नेटवर्कसम्बन्धी क्रियाकलाप हेर्न सक्छन्।"</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN सम्बन्धी सेटिङहरू खोल्नुहोस्"</string>
@@ -677,7 +675,7 @@
<string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"एपहरू"</string>
<string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"सहायता"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="7328131901589876868">"ब्राउजर (डिफल्ट ब्राउजर: Chrome)"</string>
- <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"सम्पर्कहरू"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"कन्ट्याक्टहरू"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7480359963463803511">"इमेल (डिफल्ट एप: Gmail)"</string>
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"सङ्गीत"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेभ गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेभ गर्न सकिएन।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"कम्तीमा ४ वटा वर्ण प्रयोग गर्नुहोस्"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> वटा भन्दा कम वर्ण प्रयोग गर्नुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
<string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"डिभाइसको ब्याट्रीको मिटर रिडिङ क्रममा समस्या भयो"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म राखिएको छैन"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फिंगरप्रिन्ट सेन्सर"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"प्रमाणित गर्नुहोस्"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"थप जान्नुहोस्"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> मा गई थप जान्नुहोस्"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोल्नुहोस्"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• एप सेटअप गरिएको छ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet मा कम्तीमा एउटा कार्ड हालिएको छ"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• क्यामेरा एप इन्स्टल गरिएको छ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• एप सेटअप गरिएको छ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• कम्तीमा एउटा डिभाइस उपलब्ध छ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"नोट बनाउने गर्ने सर्टकट प्रयोग गर्न नोट बनाउने डिफल्ट एप चयन गर्नुहोस्"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"सर्टकटका रूपमा Wallet एप हाल्न उक्त एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"सर्टकटका रूपमा Wallet एप हाल्न कम्तीमा एउटा कार्ड हालिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"सर्टकटका रूपमा QR कोड स्क्यानर हाल्न क्यामेरा एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home एपलाई सर्टकटका रूपमा हाल्न उक्त एप इन्स्टल गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• कम्तीमा एउटा डिभाइस उपलब्ध छ"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"नोट बनाउनेसम्बन्धी सर्टकट प्रयोग गर्न नोट बनाउने डिफल्ट एप चयन गर्नुहोस्"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"एप चयन गर्नुहोस्"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"सर्टकट थिचिराख्नुहोस्"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"रद्द गर्नुहोस्"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राथमिकता मोड अन छ"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"सहायकले सुनिरहेको छ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
+ <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index b5a6642..5dfdb86 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gezicht geverifieerd"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestigd"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestigen om te voltooien"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Ontgrendeld via gezicht"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontgrendeld via gezicht. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gezicht herkend. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hoortoestellen"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aanzetten…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan niet opslaan. Probeer het opnieuw."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan niet opslaan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gebruik minstens 4 tekens"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gebruik minder dan <xliff:g id="LENGTH">%1$d</xliff:g> tekens"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
<string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem bij het lezen van je batterijmeter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik hier voor meer informatie"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Geen wekker gezet"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Vingerafdruksensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"verifiëren"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"apparaat opgeven"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Meer informatie"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Ga voor meer informatie naar <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> openen"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• De app is ingesteld"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Er is ten minste één kaart aan Wallet toegevoegd"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Er moet een camera-app zijn geïnstalleerd"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• De app is ingesteld"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Er is ten minste één apparaat beschikbaar"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecteer een standaard notitie-app om de sneltoets voor notities maken te gebruiken"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Als je de Wallet-app wilt toevoegen als sneltoets, zorg je dat de app is geïnstalleerd"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Als je de Wallet-app wilt toevoegen als sneltoets, zorg je dat er minstens één kaart is toegevoegd"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Als je de QR-codescanner wilt toevoegen als sneltoets, zorg je dat er een camera-app is geïnstalleerd"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Als je de Home-app wilt toevoegen als sneltoets, zorg je dat de app is geïnstalleerd"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Er is minstens één apparaat beschikbaar"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecteer een standaard notitie-app om de sneltoets voor notities maken te gebruiken"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"App selecteren"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Houd de sneltoets ingedrukt"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuleren"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteitsmodus aan"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent-aandacht aan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
+ <string name="install_app" msgid="5066668100199613936">"App installeren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 76bafc6..5266083 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ମୁହଁ ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ସୁନିଶ୍ଚିତ କରାଯାଇଛି"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ସୁନିଶ୍ଚିତ କରନ୍ତୁରେ ଟାପ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ଅଡିଓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ହେଡସେଟ୍"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ଇନପୁଟ୍"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ଅନ୍ ହେଉଛି…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ଅଟୋ-ରୋଟେଟ୍"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ଅଟୋ-ରୋଟେଟ ସ୍କ୍ରିନ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ଅତିକମରେ 4ଟି କେରେକ୍ଟର ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g>ଟିରୁ କମ କେରେକ୍ଟର ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
<string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ଆଲାରାମ ସେଟ ହୋଇନାହିଁ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ଟିପଚିହ୍ନ ସେନ୍ସର୍"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ପ୍ରମାଣୀକରଣ କରନ୍ତୁ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ଡିଭାଇସ୍ ବିଷୟରେ ସୂଚନା ଲେଖନ୍ତୁ"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>ରେ ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ଆପ ସେଟ ଅପ କରାଯାଇଥିବା"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Walletରେ ଅତିକମରେ ଗୋଟିଏ କାର୍ଡ ଯୋଗ କରାଯାଇଥିବା"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ଏକ କେମେରା ଆପ ଇନଷ୍ଟଲ କରିବା"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ଆପ ସେଟ ଅପ କରାଯାଇଛି"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ଅତିକମରେ ଗୋଟିଏ ଡିଭାଇସ ଉପଲବ୍ଧ ଅଛି"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"ନୋଟଟେକିଂ ସର୍ଟକଟ ବ୍ୟବହାର କରିବାକୁ ଏକ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ୍ସ ଚୟନ କରନ୍ତୁ"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ଆପ ଚୟନ କରନ୍ତୁ"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ସର୍ଟକଟକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ବାତିଲ କରନ୍ତୁ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ପ୍ରାୟୋରିଟି ମୋଡ ଚାଲୁ ଅଛି"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ଆଟେନସନ ଚାଲୁ ଅଛି"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
+ <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0751dd2..bee58780 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਿਰਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ਪੁਸ਼ਟੀ ਕੀਤੀ ਗਈ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ਪੂਰਾ ਕਰਨ ਲਈ ਪੁਸ਼ਟੀ ਕਰੋ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ਆਡੀਓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ਹੈੱਡਸੈੱਟ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ਇਨਪੁੱਟ"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ਘੱਟੋ-ਘੱਟ 4 ਅੱਖਰ-ਚਿੰਨ੍ਹ ਵਰਤੋ"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> ਤੋਂ ਘੱਟ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਵਰਤੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
<string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ਕੋਈ ਅਲਾਰਮ ਸੈੱਟ ਨਹੀਂ"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ਡੀਵਾਈਸ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ਹੋਰ ਜਾਣੋ"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> \'ਤੇ ਹੋਰ ਜਾਣੋ"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ਐਪ ਦਾ ਸੈੱਟਅੱਪ ਹੋ ਗਿਆ ਹੈ"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• ਘੱਟੋ-ਘੱਟ ਇੱਕ ਕਾਰਡ ਨੂੰ Wallet ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ਕੈਮਰਾ ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ਐਪ ਦਾ ਸੈੱਟਅੱਪ ਹੋ ਗਿਆ ਹੈ"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• ਘੱਟੋ-ਘੱਟ ਇੱਕ ਡੀਵਾਈਸ ਉਪਲਬਧ ਹੈ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"ਨੋਟ- ਬਣਾਉਣ ਵਾਲੇ ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਚੁਣੋ"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ਐਪ ਚੁਣੋ"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ਰੱਦ ਕਰੋ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ਧਿਆਨ ਸੁਵਿਧਾ ਨੂੰ ਚਾਲੂ ਹੈ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
+ <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 5f81863..899460e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Twarz rozpoznana"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potwierdzono"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Aby zakończyć, kliknij Potwierdź"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Odblokowano skanem twarzy"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odblokowano rozpoznawaniem twarzy. Kliknij, aby kontynuować."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Twarz rozpoznana. Kliknij, aby kontynuować."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Twarz rozpoznana. Aby kontynuować, kliknij ikonę odblokowywania."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Zestaw słuchawkowy"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Wejście"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparaty słuchowe"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Włączam…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nie można zapisać. Spróbuj ponownie."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nie można zapisać."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Wpisz co najmniej 4 znaki"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Wpisz mniej znaków niż <xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Kliknij, aby uzyskać więcej informacji"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nie ustawiono alarmu"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Czytnik linii papilarnych"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"uwierzytelnij"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"otwórz urządzenie"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Więcej informacji"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Więcej informacji: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otwórz: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikacja została skonfigurowana."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Do Portfela została dodana co najmniej 1 karta."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Zainstalowano aplikację aparatu."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikacja została skonfigurowana."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Dostępne jest co najmniej 1 urządzenie."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Wybierz domyślną aplikację do obsługi notatek, której skrótu będziesz używać do funkcji notowania"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Wybierz aplikację"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Skrót – naciśnij i przytrzymaj"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Anuluj"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tryb priorytetowy jest włączony"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asystent jest aktywny"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
+ <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 9a44a53..785856e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Desbloqueado pelo rosto"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use pelo menos 4 caracteres"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressão digital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saiba mais"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saiba mais em <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• O app está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Pelo menos um cartão foi adicionado à Carteira"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Um app de câmera está instalado"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• O app está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Pelo menos um dispositivo está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar o app Carteira como um atalho, verifique se ele está instalado"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar o app Carteira como um atalho, verifique se pelo menos um cartão foi adicionado"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o leitor de código QR como um atalho, verifique se algum app de câmera está instalado"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar o app Home como um atalho, verifique se ele está instalado"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Pelo menos um dispositivo está disponível"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Selecionar app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Toque e pressione o atalho"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1150,7 +1149,7 @@
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
<string name="call_from_work_profile_title" msgid="5418253516453177114">"Não é possível fazer ligações de um app pessoal"</string>
<string name="call_from_work_profile_text" msgid="2856337395968118274">"Sua organização só permite fazer ligações usando apps de trabalho"</string>
- <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Mudar para o perfil de trabalho"</string>
<string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Instalar um app de telefone no perfil de trabalho"</string>
<string name="call_from_work_profile_close" msgid="5830072964434474143">"Cancelar"</string>
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo de prioridade ativado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9e80b25..c6612a7 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em Confirmar para concluir."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Desbloqueado com o rosto"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado com o rosto. Prima para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Prima para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Prima ícone de desbloqueio para continuar"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ausc. c/ mic. integ."</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"A ativar..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Não é possível guardar. Tente novamente."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Não é possível guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use, pelo menos, 4 carateres"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> carateres"</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>
<string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para obter mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme defin."</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressões digitais"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"entrar no dispositivo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saiba mais"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saiba mais em <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• A app está configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Foi adicionado, pelo menos, um cartão à Carteira"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Instale uma app de câmara"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• A app está configurada"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Está disponível, pelo menos, um dispositivo"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecione uma app de notas predefinida para usar o atalho de anotação"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar a app Carteira como um atalho, certifique-se de que a app está instalada"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar a app Carteira como um atalho, certifique-se de que foi adicionado, pelo menos, um cartão"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o Leitor de códigos QR como um atalho, certifique-se de que está instalada uma app de câmara"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar a app Home como um atalho, certifique-se de que a app está instalada"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Está disponível, pelo menos, um dispositivo"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione uma app de notas predefinida para usar o atalho de anotação"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Selecionar app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Toque sem soltar no atalho"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridade ativado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9a44a53..785856e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Desbloqueado pelo rosto"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use pelo menos 4 caracteres"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Use menos de <xliff:g id="LENGTH">%1$d</xliff:g> caracteres"</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>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme definido"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor de impressão digital"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autenticar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"acessar o dispositivo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Saiba mais"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Saiba mais em <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• O app está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Pelo menos um cartão foi adicionado à Carteira"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Um app de câmera está instalado"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• O app está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Pelo menos um dispositivo está disponível"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para adicionar o app Carteira como um atalho, verifique se ele está instalado"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para adicionar o app Carteira como um atalho, verifique se pelo menos um cartão foi adicionado"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para adicionar o leitor de código QR como um atalho, verifique se algum app de câmera está instalado"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para adicionar o app Home como um atalho, verifique se ele está instalado"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Pelo menos um dispositivo está disponível"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selecione um app de notas padrão para usar o atalho de anotações"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Selecionar app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Toque e pressione o atalho"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
@@ -1150,7 +1149,7 @@
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
<string name="call_from_work_profile_title" msgid="5418253516453177114">"Não é possível fazer ligações de um app pessoal"</string>
<string name="call_from_work_profile_text" msgid="2856337395968118274">"Sua organização só permite fazer ligações usando apps de trabalho"</string>
- <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Mudar para o perfil de trabalho"</string>
<string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Instalar um app de telefone no perfil de trabalho"</string>
<string name="call_from_work_profile_close" msgid="5830072964434474143">"Cancelar"</string>
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo de prioridade ativado"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index b05eee0..a7a2731 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Chip autentificat"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atinge Confirm pentru a finaliza"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"S-a deblocat folosind fața"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S-a deblocat cu ajutorul feței. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Chipul a fost recunoscut. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apasă pictograma Deblocare ca să continui."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Căști"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Intrare"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparate auditive"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Se activează..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nu se poate salva. Încearcă din nou."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nu se poate salva."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Folosește minimum 4 caractere."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Folosește maximum <xliff:g id="LENGTH">%1$d</xliff:g> caractere"</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>
<string name="basic_status" msgid="2315371112182658176">"Deschide conversația"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atinge pentru mai multe informații"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nicio alarmă setată"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor de amprentă"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifică-te"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"Accesează dispozitivul"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Află mai multe"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Află mai multe la <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Deschide <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplicația este configurată"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Cel puțin un card a fost adăugat în Portofel"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Instalează o aplicație pentru camera foto"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplicația este configurată"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Este disponibil cel puțin un dispozitiv"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Selectează o aplicație prestabilită pentru note ca să folosești comanda rapidă de luat note"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Pentru a adăuga aplicația Portofel drept comandă rapidă, asigură-te că aplicația este instalată"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Pentru a adăuga aplicația Portofel drept comandă rapidă, asigură-te că ai adăugat cel puțin un card"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Pentru a adăuga Scanner de coduri QR drept comandă rapidă, asigură-te că este instalată o aplicație pentru camera foto"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Pentru a adăuga aplicația Home drept comandă rapidă, asigură-te că aplicația este instalată"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Este disponibil cel puțin un dispozitiv"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Selectează o aplicație prestabilită pentru note ca să folosești comanda rapidă de luat note"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Selectează aplicația"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Atinge lung comanda rapidă"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Anulează"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modul Cu prioritate este activat"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistentul este atent"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c342928..279d9a6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицо распознано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Подтверждено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Нажмите \"Подтвердить\""</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Разблокировано сканированием лица"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблокировано сканированием лица. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицо распознано. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицо распознано. Нажмите на значок разблокировки."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудиоустройство"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Устройство ввода"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слуховые аппараты"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включение…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не удалось сохранить. Повторите попытку."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не удалось сохранить."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Минимальное количество символов – 4"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Максимальное количество символов – <xliff:g id="LENGTH">%1$d</xliff:g>."</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
<string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удалось узнать уровень заряда батареи"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Нет будильников"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер отпечатков пальцев"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"выполнить аутентификацию"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"указать устройство"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Подробнее"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Подробнее: <xliff:g id="URL">%s</xliff:g>."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Открыть \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Приложение установлено."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• В Кошельке есть хотя бы одна карта."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Установлено приложение камеры."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Приложение установлено."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Доступно хотя бы одно устройство."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Выберите стандартное приложение для заметок, которое будет открываться при нажатии кнопки быстрого доступа."</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Выбрать приложение"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Нажмите и удерживайте ярлык"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Отмена"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим \"Только важные\" включен"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Ассистент готов слушать"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
+ <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 633d5d8..ddca7f5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"මුහුණ සත්යාපන කළා"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"තහවුරු කළා"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"සම්පූර්ණ කිරීමට තහවුරු කරන්න තට්ටු කර."</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"මුහුණ මගින් අගුළු හරින ලදි"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"මුහුණ මගින් අගුලු හරින ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ශ්රව්ය"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"හෙඩ්සෙටය"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ආදානය"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ශ්රවණාධාරක"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ක්රියාත්මක කරමින්…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්රීය කරකැවීම"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්රීයව-භ්රමණය වන තිරය"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"සුරැකිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"සුරැකිය නොහැකිය."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"අවම වශයෙන් අනුලකුණු 4ක් භාවිතා කරන්න"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"අනුලකුණු <xliff:g id="LENGTH">%1$d</xliff:g>කට වඩා අඩුවෙන් භාවිතා කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
<string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ඔබගේ බැටරි මනුව කියවීමේ දෝෂයකි"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"තවත් තොරතුරු සඳහා තට්ටු කරන්න"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"එලාම සකසා නැත"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ඇඟිලි සලකුණු සංවේදකය"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"සත්යාපනය කරන්න"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"උපාංගය ඇතුළු කරන්න"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"තව දැන ගන්න"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g> තුළින් තව දැන ගන්න"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> විවෘත කරන්න"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• යෙදුම සකසා ඇත"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet වෙත අවම වශයෙන් එක කාඩ්පතක් එක් කර ඇත"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• කැමරා යෙදුමක් ස්ථාපන කරන්න"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• යෙදුම සකසා ඇත"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• අවම වශයෙන් එක උපාංගයක් ලැබේ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"සටහන් ගැනීමේ කෙටිමඟ භාවිතා කිරීමට පෙරනිමි සටහන් යෙදුමක් තෝරන්න"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"යෙදුම තෝරන්න"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ස්පර්ශ කර අල්ලා සිටීමේ කෙටිමඟ"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"අවලංගු කරන්න"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ප්රමුඛතා මාදිලිය සක්රීයයි"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"සහයක අවධානය යොමු කරයි"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
+ <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 6764568..996f454 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Tvár bola overená"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrdené"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Overenie dokončíte klepnutím na Potvrdiť"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Odomknuté tvárou"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odomknuté tvárou. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Tvár bola rozpoznaná. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Tvár bola rozpoznaná. Pokračujte stlačením ikony odomknutia"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Náhlavná súprava"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Načúvadlá"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapína sa…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nedá sa uložiť. Skúste to znova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nedá sa uložiť."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Použite aspoň štyri znaky"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Použite menej znakov než <xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Žiadny budík"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor odtlačkov prstov"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"overte"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstúpte do zariadenia"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Ďalšie informácie"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Viac sa dozviete na <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvoriť <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikácia je nastavená"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Do Peňaženky bola pridaná minimálne jedna karta"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Nainštalujte si aplikáciu kamery"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikácia je nastavená"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• K dispozícii je minimálne jedno zariadenie"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Vyberte predvolenú aplikáciu na písanie poznámok, ku ktorej priradíte skratku pre poznámky"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Výber aplikácie"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pridržte skratku"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Zrušiť"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Režim priority je zapnutý"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Pozornosť Asistenta je zapnutá"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
+ <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2cbf0b6..6bebdcc 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Pristnost obraza je potrjena"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potrjeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Za dokončanje se dotaknite »Potrdite«"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Odklenjeno z obrazom"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odklenjeno z obrazom. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obraz je prepoznan. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obraz je prepoznan. Za nadaljevanje pritisnite ikono za odklepanje."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvok"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalke z mikrofonom"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Vklapljanje …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ni mogoče shraniti. Poskusite znova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ni mogoče shraniti."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Uporabite vsaj 4 znake."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Uporabite manj kot <xliff:g id="LENGTH">%1$d</xliff:g> znakov."</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>
<string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dotaknite se za več informacij"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ni nastavljenih alarmov"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Tipalo prstnih odtisov"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"preverjanje pristnosti"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"vstop v napravo"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Več o tem"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Več informacij je na voljo na strani <xliff:g id="URL">%s</xliff:g>."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Odpri aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikacija mora biti nastavljena."</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Vsaj ena kartica mora biti dodana v Denarnico."</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Namestite fotografsko aplikacijo."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikacija mora biti nastavljena."</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Na voljo mora biti vsaj ena naprava."</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Izberite privzeto aplikacijo za zapiske, ki jo želite povezati z bližnjico do ustvarjanja zapiskov."</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Če želite aplikacijo Denarnica dodati kot bližnjico, poskrbite, da je aplikacija nameščena."</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Če želite aplikacijo Denarnica dodati kot bližnjico, poskrbite, da je dodana vsaj ena kartica."</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Če želite optični bralnik kod QR dodati kot bližnjico, poskrbite, da je nameščena fotografska aplikacija."</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Če želite aplikacijo Home dodati kot bližnjico, poskrbite, da je aplikacija nameščena."</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Na voljo mora biti vsaj ena naprava."</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Izberite privzeto aplikacijo za zapiske, ki jo želite povezati z bližnjico do ustvarjanja zapiskov."</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Izbira aplikacije"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pridržite bližnjico"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Prekliči"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prednostni način je vklopljen."</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Zaznavanje pomočnika je vklopljeno."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
+ <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 8d87277..24d5fca 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Fytyra u vërtetua"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Konfirmuar"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trokit \"Konfirmo\" për ta përfunduar"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"U shkyç me fytyrë"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"U shkyç me fytyrë. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Fytyra u njoh. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Fytyra u njoh. Shtyp ikonën e shkyçjes për të vazhduar."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kufje me mikrofon"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Hyrja"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparatet e dëgjimit"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Po aktivizohet…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nuk mund të ruhet. Provo përsëri."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nuk mund të ruhet."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Përdor të paktën 4 karaktere"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Përdor më pak se <xliff:g id="LENGTH">%1$d</xliff:g> karaktere"</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>
<string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nuk është caktuar asnjë alarm"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensori i gjurmës së gishtit"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"për ta vërtetuar"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"për të hyrë në pajisje"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Mëso më shumë"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Mëso më shumë në <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Hap \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Aplikacioni është konfiguruar"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Të paktën një kartë të jetë shtuar në \"Portofol\""</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Të instalosh një aplikacion të kamerës"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Aplikacioni është konfiguruar"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Ofrohet të paktën një pajisje"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Zgjidh një aplikacion të parazgjedhur shënimesh për të përdorur shkurtoren e mbajtjes së shënimeve"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Zgjidh aplikacionin"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Prek dhe mbaj shtypur shkurtoren"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Anulo"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modaliteti i përparësisë aktiv"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Vëmendja e \"Asistentit\" aktive"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
+ <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1206198..9ca97b9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лице је потврђено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврђено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Додирните Потврди да бисте завршили"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Откључано је лицем"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Откључано је лицем. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лице је препознато. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лице препознато. Притисните икону откључавања за наставак."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалице"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Унос"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Укључује се..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аутоматска ротација"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аутоматско ротирање екрана"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Чување није успело. Пробајте поново."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Чување није успело."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Користите бар 4 знака"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Користите мањи број знакова од <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Није подешен"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отисак прста"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"потврдите идентитет"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"унесите уређај"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Сазнајте више"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Сазнајте више на <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворите: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• да је апликација подешена"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• да је у Новчаник додата барем једна картица"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• да сте инсталирали апликацију за камеру"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• да је апликација подешена"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• да је доступан барем један уређај"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Изаберите подразумевану апликацију за белешке да бисте користили пречицу за прављење белешки"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Изабери апликацију"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Додирните и задржите пречицу"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Откажи"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетни режим је укључен"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Помоћник је у активном стању"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
+ <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1e776d1..82468cb 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet har autentiserats"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekräftat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Upplåst med ansiktslås"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Upplåst med ansiktslås. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet har identifierats. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ljud"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingång"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörapparater"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverar …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Det gick inte att spara. Försök igen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Det gick inte att spara."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Använd minst 4 tecken"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Använd färre än <xliff:g id="LENGTH">%1$d</xliff:g> tecken"</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>
<string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryck för mer information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Inget inställt alarm"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeravtryckssensor"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentisera"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ange enhet"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Läs mer"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Läs mer på <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Öppna <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• appen har konfigurerats"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• minst ett kort har lagts till i Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• installera en kameraapp"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• appen har konfigurerats"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• minst en enhet är tillgänglig"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Välj en standardapp för anteckningar om du vill använda genvägen för anteckningar"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Välj app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Tryck länge på genvägen"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Avbryt"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetsläge är aktiverat"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistenten är aktiverad"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
+ <string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 38987fa..ef92eb6 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Uso umethibitishwa"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Imethibitishwa"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Gusa Thibitisha ili ukamilishe"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Inafunguliwa kwa kutumia uso"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Uso umetambuliwa. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili uendelee."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Vifaa vya sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vifaa vya kuingiza sauti"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Visaidizi vya kusikia"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inawasha..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Imeshindwa kuhifadhi. Jaribu tena."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Imeshindwa kuhifadhi."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Tumia angalau herufi 4"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Hupaswi kuzidi herufi <xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Tatizo la kusoma mita ya betri yako"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Gusa ili upate maelezo zaidi"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Hujaweka kengele"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Kitambua alama ya kidole"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"thibitisha"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"weka kifaa"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Pata maelezo zaidi"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Pata maelezo zaidi katika <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Fungua <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Programu hii imewekewa mipangilio"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Angalau kadi moja imewekwa kwenye Pochi"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Sakinisha programu ya kamera"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Programu hii imewekewa mipangilio"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Angalau kifaa kimoja kinapatikana"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Chagua programu chaguomsingi ya madokezo ili utumie njia ya mkato ya kuandika madokezo"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ili uweke programu ya Pochi kuwa njia ya mkato, hakikisha umesakinisha programu hiyo"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ili uweke programu ya Pochi kuwa njia ya mkato, hakikisha umeweka angalau kadi moja"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ili uweke kichanganuzi cha msimbo wa QR kuwa njia ya mkato, hakikisha umesakinisha programu ya kamera"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ili uweke programu ya Google Home kuwa njia ya mkato, hakikisha umesakinisha programu hiyo"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Angalau kifaa kimoja kinapatikana"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Chagua programu chaguomsingi ya madokezo ili utumie njia ya mkato ya kuandika madokezo"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Chagua programu"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Gusa na ushikilie njia ya mkato"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Ghairi"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Hali ya kipaumbele imewashwa"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Programu ya Mratibu imewashwa"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
+ <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw410dp-land/dimens.xml b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
index c4d9b9b..6045606 100644
--- a/packages/SystemUI/res/values-sw410dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
@@ -18,4 +18,8 @@
<!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
<dimen name="biometric_auth_pattern_view_size">248dp</dimen>
<dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+ <!-- Power Menu Lite -->
+ <dimen name="global_actions_button_size">96dp</dimen>
+ <dimen name="global_actions_button_padding">38dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 1e883e6..b277f55 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"முகம் அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"முகத்தால் அன்லாக் செய்யப்பட்டது"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அன்லாக் ஐகானை அழுத்தவும்."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ஆடியோ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ஹெட்செட்"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"உள்ளீடு"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"செவித்துணைக் கருவி"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ஆன் செய்கிறது…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"சேமிக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"சேமிக்க முடியவில்லை."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"குறைந்தது 4 எழுத்துகளைப் பயன்படுத்துங்கள்"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> எழுத்துகளுக்குக் குறைவாகப் பயன்படுத்துங்கள்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
<string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"அலாரம் எதுவுமில்லை"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"கைரேகை சென்சார்"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"அங்கீகரி"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"சாதனத்தைத் திற"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"மேலும் அறிக"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"மேலும் அறிக: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸைத் திற"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• இந்த ஆப்ஸ் அமைக்கப்பட்டிருக்க வேண்டும்"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Walletடில் குறைந்தபட்சம் ஒரு கார்டாவது சேர்க்கப்பட்டிருக்க வேண்டும்"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• கேமரா ஆப்ஸ் நிறுவப்பட்டிருக்க வேண்டும்"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• இந்த ஆப்ஸ் அமைக்கப்பட்டிருக்க வேண்டும்"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• குறைந்தபட்சம் ஒரு சாதனமாவது கிடைக்க வேண்டும்"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"குறிப்பெடுத்தல் ஷார்ட்கட்டைப் பயன்படுத்த, குறிப்பெடுப்பதற்கான இயல்புநிலை ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ஆப்ஸைத் தேர்ந்தெடு"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"ஷார்ட்கட்டை தொட்டுப் பிடிக்கவும்"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ரத்துசெய்"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"முன்னுரிமைப் பயன்முறை இயக்கத்தில் உள்ளது"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"அசிஸ்டண்ட்டின் கவனம் இயக்கத்தில் உள்ளது"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
+ <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ffe4b17..a6cbf3d 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -132,7 +132,7 @@
<string name="accessibility_unlock_button" msgid="3613812140816244310">"అన్లాక్ చేయబడింది"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"పరికరం లాక్ చేయబడింది"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"ముఖాన్ని స్కాన్ చేస్తోంది"</string>
- <string name="accessibility_send_smart_reply" msgid="8885032190442015141">"పంపు"</string>
+ <string name="accessibility_send_smart_reply" msgid="8885032190442015141">"పంపండి"</string>
<string name="cancel" msgid="1089011503403416730">"రద్దు చేయండి"</string>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"నిర్ధారించండి"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"మళ్లీ ట్రై చేయండి"</string>
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ముఖం ప్రామాణీకరించబడింది"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"నిర్ధారించబడింది"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"పూర్తి చేయడానికి \"నిర్ధారించు\" నొక్కండి"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ముఖం ద్వారా అన్లాక్ చేయబడింది"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ముఖం ద్వారా అన్లాక్ చేయబడింది. కొనసాగించడానికి నొక్కండి."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ముఖం గుర్తించబడింది. కొనసాగించడానికి నొక్కండి."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ముఖం గుర్తించబడింది. కొనసాగడానికి అన్లాక్ చిహ్నం నొక్కండి."</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"సేవ్ చేయడం సాధ్యపడదు. మళ్లీ ట్రై చేయండి."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"సేవ్ చేయడం సాధ్యపడదు."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"కనీసం 4 అక్షరాలను ఉపయోగించండి"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> కంటే తక్కువ అక్షరాలను ఉపయోగించండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్బోర్డ్కు కాపీ చేయబడింది."</string>
<string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
@@ -1048,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్ను చదవడంలో సమస్య"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"అలారం సెట్ చేయలేదు"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"స్క్రీన్ లాక్ను ఎంటర్ చేయండి"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"వేలిముద్ర సెన్సార్"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ప్రామాణీకరించండి"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"పరికరాన్ని ఎంటర్ చేయండి"</string>
@@ -1127,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"మరింత తెలుసుకోండి"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>లో మరింత తెలుసుకోండి"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>ను తెరవండి"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• యాప్ సెటప్ చేయబడి ఉందని"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Walletకు కనీసం ఒక కార్డ్ అయినా జోడించబడి ఉందని"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• కెమెరా యాప్ ఇన్స్టాల్ చేసి ఉందని"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• యాప్ సెటప్ చేయబడి ఉందని"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• కనీసం ఒక పరికరమైనా అందుబాటులో ఉందని"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"నోట్టేకింగ్ షార్ట్కట్ను ఉపయోగించడానికి ఆటోమేటిక్ సెట్టింగ్ నోట్స్ యాప్ను ఎంచుకోండి"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, కనీసం ఒక కార్డ్ జోడించబడిందని నిర్ధారించుకోండి"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR కోడ్ స్కానర్ను షార్ట్కట్గా జోడించడానికి, కెమెరా యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• కనీసం ఒక పరికరమైనా అందుబాటులో ఉందని"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"నోట్టేకింగ్ షార్ట్కట్ను ఉపయోగించడానికి ఆటోమేటిక్ సెట్టింగ్ నోట్స్ యాప్ను ఎంచుకోండి"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"యాప్ను ఎంచుకోండి"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"షార్ట్కట్ను తాకి, నొక్కి ఉంచు"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"రద్దు చేయండి"</string>
@@ -1161,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ప్రయారిటీ మోడ్ ఆన్లో ఉంది"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant అటెన్షన్ ఆన్లో ఉంది"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string>
+ <string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f408508..4b15309 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ยืนยันแล้ว"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"แตะยืนยันเพื่อดำเนินการให้เสร็จสมบูรณ์"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"ปลดล็อกด้วยใบหน้าแล้ว"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"จดจำใบหน้าได้ กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"เสียง"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ชุดหูฟัง"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"อินพุต"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"กำลังเปิด..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"หมุนอัตโนมัติ"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"หมุนหน้าจออัตโนมัติ"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"บันทึกไม่ได้ โปรดลองอีกครั้ง"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"บันทึกไม่ได้"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ใช้อักขระอย่างน้อย 4 ตัว"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"ใช้อักขระไม่เกิน <xliff:g id="LENGTH">%1$d</xliff:g> ตัว"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
<string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"พบปัญหาในการอ่านเครื่องวัดแบตเตอรี่"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"แตะดูข้อมูลเพิ่มเติม"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ไม่มีการตั้งปลุก"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"เซ็นเซอร์ลายนิ้วมือ"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ตรวจสอบสิทธิ์"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"เข้าถึงอุปกรณ์"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"ดูข้อมูลเพิ่มเติม"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"ดูข้อมูลเพิ่มเติมที่ <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"เปิด <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• แอปได้รับการตั้งค่าแล้ว"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• มีการเพิ่มบัตรลงใน Wallet อย่างน้อย 1 รายการ"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• ติดตั้งแอปกล้อง"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• แอปได้รับการตั้งค่าแล้ว"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• มีอุปกรณ์พร้อมใช้งานอย่างน้อย 1 รายการ"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"เลือกแอปโน้ตเริ่มต้นเพื่อใช้ทางลัดการจดบันทึก"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"หากต้องการเพิ่มแอป Wallet เป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปแล้ว"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"หากต้องการเพิ่มแอป Wallet เป็นทางลัด โปรดตรวจสอบว่าได้เพิ่มบัตรอย่างน้อย 1 ใบแล้ว"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"หากต้องการเพิ่มเครื่องมือสแกนคิวอาร์โค้ดเป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปกล้องแล้ว"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"หากต้องการเพิ่มแอป Home เป็นทางลัด โปรดตรวจสอบว่าได้ติดตั้งแอปแล้ว"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• มีอุปกรณ์พร้อมใช้งานอย่างน้อย 1 รายการ"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"เลือกแอปโน้ตเริ่มต้นเพื่อใช้ทางลัดการจดบันทึก"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"เลือกแอป"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"แตะแป้นพิมพ์ลัดค้างไว้"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"ยกเลิก"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"โหมดลำดับความสำคัญเปิดอยู่"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"การเรียกใช้งาน Assistant เปิดอยู่"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
+ <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 402b4f1..3997539 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Na-authenticate ang mukha"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Nakumpirma"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"I-tap ang Kumpirmahin para kumpletuhin"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Na-unlock gamit ang mukha"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Na-unlock gamit ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nakilala ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nakilala ang mukha. Pindutin ang unlock para magpatuloy."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Mga hearing aid"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ino-on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Hindi ma-save. Subukan ulit."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Hindi ma-save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gumamit ng hindi bababa sa 4 na character"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Gumamit ng mas kaunti sa <xliff:g id="LENGTH">%1$d</xliff:g> (na) character"</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>
<string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nagkaproblema sa pagbabasa ng iyong battery meter"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"I-tap para sa higit pang impormasyon"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Walang alarm"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"ilagay ang lock ng screen"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor para sa fingerprint"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"i-authenticate"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ilagay ang device"</string>
@@ -1128,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Matuto pa"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Matuto pa sa <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buksan ang <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Na-set up ang app"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• May kahit isang card na idinagdag sa Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Mag-install ng camera app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Na-set up ang app"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• May kahit isang device na available"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Pumili ng default na notes app para magamit ang shortcut sa pagtatala"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Para maidagdag ang Wallet app bilang shortcut, siguraduhing naka-install ang app"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Para maidagdag ang Wallet app bilang shortcut, siguraduhing may naidagdag na kahit isang card man lang"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Para maidagdag ang scanner ng QR code bilang shortcut, siguraduhing may naka-install na camera app"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Para maidagdag ang Home app bilang shortcut, siguraduhing naka-install ang app"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• May kahit isang device na available"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Pumili ng default na app ng mga tala para magamit ang shortcut sa paggawa ng tala"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Pumili ng app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Pindutin nang matagal: shortcut"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Kanselahin"</string>
@@ -1162,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Naka-on ang Priority mode"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Naka-on ang atensyon ng Assistant"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
+ <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ed3a36f..395c07c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yüz kimliği doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Onaylandı"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamak için Onayla\'ya dokunun"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Cihazın kilidini yüzünüzle açtınız"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Cihazın kilidini yüzünüzle açtınız. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yüzünüz tanındı. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ses"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Mikrofonlu kulaklık"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"İşitme cihazları"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Açılıyor…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kaydedilemiyor. Tekrar deneyin."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kaydedilemiyor."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"En az 4 karakter kullanın."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"En fazla <xliff:g id="LENGTH">%1$d</xliff:g> karakter kullanın"</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>
<string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Daha fazla bilgi için dokunun"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm yok"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Parmak izi sensörü"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"kimlik doğrulaması yapın"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"cihaz girin"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Daha fazla bilgi"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Daha fazla bilgiyi <xliff:g id="URL">%s</xliff:g> sayfasında bulabilirsiniz"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasını aç"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Uygulama kurulmuş olmalıdır"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Cüzdan\'a en az bir kart eklenmelidir"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kamera uygulaması yüklenmelidir"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Uygulama kurulmuş olmalıdır"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• En az bir cihaz mevcut olmalıdır"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Not alma kısayolunu kullanmak için varsayılan bir notlar uygulaması seçin"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Uygulama seçin"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Kısayola dokunup basılı tutun"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"İptal"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Öncelik modu etkin"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistan dinliyor"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
+ <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index e4f27a0..86b609b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Обличчя автентифіковано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Розблоковано (фейс-контроль)"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейсконтроль). Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Обличчя розпізнано. Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Обличчя розпізнано. Натисніть значок розблокування."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудіопристрій"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Джерело сигналу"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухові апарати"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Увімкнення…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автообертання"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не вдалося зберегти. Повторіть спробу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не вдалося зберегти."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Введіть принаймні 4 символи"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Кількість символів має бути менше ніж <xliff:g id="LENGTH">%1$d</xliff:g>"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
<string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не вдалось отримати дані про рівень заряду акумулятора"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Немає будильників"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер відбитків пальців"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"пройти автентифікацію"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Докладніше"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Докладніше: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Відкрити <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Додаток налаштовано"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Принаймні одну картку додано в Гаманець"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Встановлено додаток для камери"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Додаток налаштовано"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Принаймні один пристрій доступний"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Виберіть стандартний додаток для нотаток, щоб створювати їх за допомогою ярлика"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Вибрати додаток"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Натисніть і утримуйте ярлик"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Скасувати"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим пріоритету ввімкнено"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Асистента активовано"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
+ <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index dceeb29..2069d26 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چہرے کی تصدیق ہو گئی"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تصدیق شدہ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"مکمل کرنے کیلئے \'تصدیق کریں\' تھپتھپائیں"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"چہرے سے غیر مقفل کیا گیا"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"چہرے سے انلاک کیا گیا۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کیلئے انلاک آئیکن دبائیں۔"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"آڈیو"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ہیڈ سیٹ"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ان پٹ"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعتی آلات"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"آن ہو رہا ہے…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"محفوظ نہیں کیا جا سکا۔ پھر کوشش کریں۔"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"محفوظ نہیں کیا جا سکا۔"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"کم از کم 4 حروف استعمال کریں"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"<xliff:g id="LENGTH">%1$d</xliff:g> حروف سے کم استعمال کریں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
<string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"کوئی الارم سیٹ نہیں ہے"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"فنگر پرنٹ سینسر"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"تصدیق کریں"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"آلہ درج کریں"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"مزید جانیں"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"مزید جاننے کیلئے <xliff:g id="URL">%s</xliff:g> ملاحظہ کریں"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> کھولیں"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• ایپ سیٹ اپ ہو گئی ہے"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• والٹ میں کم از کم ایک کارڈ شامل کیا گیا ہے"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• کیمرا ایپ انسٹال کریں"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• ایپ سیٹ اپ ہو گئی ہے"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• کم از کم ایک آلہ دستیاب ہے"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"نوٹ لینے والے شارٹ کٹ کا استعمال کرنے کے لیے ڈیفالٹ نوٹس ایپ منتخب کریں"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"ایپ منتخب کریں"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"شارٹ کٹ ٹچ کریں اور دبائے رکھیں"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"منسوخ کریں"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ترجیحی موڈ آن ہے"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"اسسٹنٹ کی توجہ آن ہے"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
+ <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index dce06aa..e6a9414 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yuzingiz aniqlandi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Tasdiqlangan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tasdiqlash uchun tegining"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Yuz bilan ochildi"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Yuz orqali ochildi. Davom etish uchun bosing."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yuz aniqlandi. Davom etish uchun bosing."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yuz aniqlandi. Davom etish uchun ochish belgisini bosing."</string>
@@ -1005,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Saqlanmadi. Qayta urining."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Saqlanmadi."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Parolga kamida 4 ta belgi kiriting."</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Kiritiladigan belgilar <xliff:g id="LENGTH">%1$d</xliff:g> tadan oshmasin"</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>
<string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
@@ -1048,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Batafsil axborot olish uchun bosing"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Signal sozlanmagan"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Barmoq izi skaneri"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifikatsiya"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"qurilmani ochish"</string>
@@ -1127,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Batafsil"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Batafsil: <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ochish: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Ilova sozlangan"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Kamida bitta kartochka Wallet xizmatiga qoʻshilgan"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Kamera ilovasini oʻrnating"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Ilova sozlangan"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Kamida bitta qurilma mavjud"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Qayd yozish yorligʻidan foydalanish uchun birlamchi qayd ilovasini tanlang"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet ilovasini yorliq sifatida qoʻshish uchun ilova oʻrnatilganiga ishonch hosil qiling"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet ilovasini yorliq sifatida qoʻshish uchun kamida bitta karta kiritilganiga ishonch hosil qiling"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"QR kod skanerini yorliq sifatida qoʻshish uchun kamera ilovasi oʻrnatilganiga ishonch hosil qiling"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home ilovasini yorliq sifatida qoʻshish uchun ilova oʻrnatilganiga ishonch hosil qiling"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Kamida bitta qurilma mavjud"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Qayd yozish yorligʻidan foydalanish uchun birlamchi qayd ilovasini tanlang"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Ilovani tanlang"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Bosib turish yorligʻi"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Bekor qilish"</string>
@@ -1161,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imtiyozli rejim yoniq"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent diqqati yoniq"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string>
+ <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bf4c3ed..33ae91e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Đã xác thực khuôn mặt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ðã xác nhận"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Nhấn vào Xác nhận để hoàn tất"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Đã mở khoá bằng khuôn mặt"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Đã mở khoá bằng khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Đã nhận diện khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để tiếp tục."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Âm thanh"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Tai nghe"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Thiết bị đầu vào"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Thiết bị trợ thính"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Đang bật…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Không lưu được. Hãy thử lại."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Không lưu được."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Sử dụng ít nhất 4 ký tự"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Hãy dùng ít hơn <xliff:g id="LENGTH">%1$d</xliff:g> ký tự"</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 bảng nhớ tạm."</string>
<string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Chưa đặt chuông báo"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Cảm biến vân tay"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"xác thực"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"truy cập thiết bị"</string>
@@ -1128,12 +1127,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Tìm hiểu thêm"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Tìm hiểu thêm tại <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Mở <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• Ứng dụng được thiết lập"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Thêm ít nhất một thẻ vào Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Cài đặt một ứng dụng máy ảnh"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• Ứng dụng được thiết lập"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Có ít nhất một thiết bị đang hoạt động"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Chọn một ứng dụng ghi chú mặc định để dùng lối tắt ghi chú"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Chọn ứng dụng"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Chạm và giữ phím tắt"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Huỷ"</string>
@@ -1162,4 +1167,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Chế độ ưu tiên đang bật"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Trợ lý đang bật"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
+ <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b43cb20..e167c61 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"启用 USB"</string>
<string name="learn_more" msgid="4690632085667273811">"了解详情"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"已停用 Extend Unlock"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"已停用延长解锁"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"正在将屏幕截图保存到工作资料…"</string>
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔身份验证成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已确认"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"点按“确认”即可完成"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"已用面孔解锁"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已通过面孔识别解锁。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"识别出面孔。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"识别出面孔。按下解锁图标即可继续。"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音频"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳机"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"输入"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助听器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在开启…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动屏幕旋转"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"无法保存,请重试。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"无法保存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"必须至少 4 个字符"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"必须少于 <xliff:g id="LENGTH">%1$d</xliff:g> 个字符"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build 号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将 Build 号复制到剪贴板。"</string>
<string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未设置闹钟"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"输入屏幕解锁信息"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指纹传感器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"身份验证"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"进入设备"</string>
@@ -1128,12 +1126,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"了解详情"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"如需了解详情,请前往 <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"打开<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• 应用已设置完毕"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• 至少已将一张银行卡添加到钱包"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• 安装相机应用"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• 应用已设置完毕"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• 至少有一台设备可用"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"选择默认记事应用即可使用记事快捷方式"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"若要将 Google 钱包应用添加为快捷方式,请确保已安装该应用"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"若要将 Google 钱包应用添加为快捷方式,请确保至少已添加一张银行卡"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"若要将二维码扫描器添加为快捷方式,请确保已安装相机应用"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"若要将 Home 应用添加为快捷方式,请确保已安装该应用"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• 至少有一台设备可用"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"选择默认记事应用即可使用记事快捷方式"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"选择应用"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"轻触并按住快捷方式"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"取消"</string>
@@ -1162,4 +1160,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"已开启优先模式"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"已开启 Google 助理感知功能"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
+ <string name="install_app" msgid="5066668100199613936">"安装应用"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 89876ff..6c6f504 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔已經驗證"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"已使用面孔解鎖"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已使用面孔解鎖。按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"已識別面孔。按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"已識別面孔。按解鎖圖示即可繼續。"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在開啟…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"請至少使用 4 個字元"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"請使用少於 <xliff:g id="LENGTH">%1$d</xliff:g> 個字元"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"輸入螢幕鎖定憑證"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋感應器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
@@ -1128,12 +1126,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"瞭解詳情"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"詳情請瀏覽 <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• 應用程式已完成設定"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• 已新增至少一張卡至「錢包」"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• 安裝相機應用程式"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• 應用程式已完成設定"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• 至少一部裝置可用"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"選取筆記快速鍵所用的預設筆記應用程式"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"選取應用程式"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"輕觸並按住快速鍵"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"取消"</string>
@@ -1162,4 +1166,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先模式已開啟"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"「Google 助理」感應功能已開啟"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
+ <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index baf157f..888908a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔驗證成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認完畢"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕觸 [確認] 完成驗證設定"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"裝置已透過你的臉解鎖"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"裝置已透過你的臉解鎖,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"臉孔辨識完成,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"臉孔辨識完成,按下「解鎖」圖示即可繼續操作。"</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"開啟中…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
@@ -362,7 +360,7 @@
<string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"臉孔辨識完成"</string>
<string name="keyguard_retry" msgid="886802522584053523">"向上滑動即可重試"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
- <string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
+ <string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於貴機構"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
<string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"這是「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」提供的裝置"</string>
<string name="phone_hint" msgid="6682125338461375925">"滑動手機圖示即可啟用"</string>
@@ -435,7 +433,7 @@
<string name="quick_settings_financed_disclosure_named_management" msgid="2307703784594859524">"這是「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」提供的裝置"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="4137564460025113168">"這部裝置的擁有者為貴機構,並已透過「<xliff:g id="VPN_APP">%1$s</xliff:g>」連線到網際網路"</string>
<string name="quick_settings_disclosure_named_management_named_vpn" msgid="2169227918166358741">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」,並已透過「<xliff:g id="VPN_APP">%2$s</xliff:g>」連線到網際網路"</string>
- <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"這部裝置的擁有者為貴機構"</string>
+ <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"此裝置屬於貴機構"</string>
<string name="quick_settings_disclosure_named_management" msgid="3476472755775165827">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」"</string>
<string name="quick_settings_disclosure_management_vpns" msgid="929181757984262902">"這部裝置的擁有者為貴機構,並已透過 VPN 連線到網際網路"</string>
<string name="quick_settings_disclosure_named_management_vpns" msgid="3312645578322079185">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>」,並已透過 VPN 連線到網際網路"</string>
@@ -456,7 +454,7 @@
<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_financed_description_named_management" msgid="6108439201399938668">"「<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g>」或許可以存取這部裝置的相關資料、管理應用程式及變更裝置設定。\n\n如有任何疑問,請與「<xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>」聯絡。"</string>
- <string name="monitoring_description_management" msgid="4308879039175729014">"這部裝置的擁有者為貴機構。\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>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"貴機構已為你的工作資料夾安裝憑證授權單位憑證。你的安全網路流量可能會受到監控或修改。"</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"這個裝置已安裝憑證授權單位憑證。你的安全網路流量可能會受到監控或修改。"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"至少要有 4 個半形字元"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"不得超過 <xliff:g id="LENGTH">%1$d</xliff:g> 個半形字元"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
@@ -1049,6 +1046,7 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
+ <string name="accessibility_bouncer" msgid="5896923685673320070">"輸入螢幕鎖定憑證"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋感應器"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"驗證"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"進入裝置"</string>
@@ -1128,12 +1126,18 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"瞭解詳情"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"如要瞭解詳情,請前往 <xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• 完成應用程式設定"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• 錢包中至少要有一張卡片"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• 安裝相機應用程式"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• 完成應用程式設定"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• 至少要有一部可用裝置"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"如要使用筆記捷徑,請選取預設的記事應用程式"</string>
+ <!-- no translation found for wallet_quick_affordance_unavailable_install_the_app (7298552910007208368) -->
+ <skip />
+ <!-- no translation found for wallet_quick_affordance_unavailable_configure_the_app (4387433357429873258) -->
+ <skip />
+ <!-- no translation found for qr_scanner_quick_affordance_unavailable_explanation (3049582306241150946) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_install_the_app (6187820778998446168) -->
+ <skip />
+ <!-- no translation found for home_quick_affordance_unavailable_configure_the_app (7953595390775156839) -->
+ <skip />
+ <!-- no translation found for notes_app_quick_affordance_unavailable_explanation (4796955161600178530) -->
+ <skip />
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"選取應用程式"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"按住快速鍵"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"取消"</string>
@@ -1162,4 +1166,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先模式已開啟"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Google 助理感知功能已開啟"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
+ <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 46b9a6c..e57e60b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -142,8 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ubuso bufakazelwe ubuqiniso"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kuqinisekisiwe"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Thepha okuthi Qinisekisa ukuze uqedele"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
- <skip />
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Vula ngobuso"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Vula ngobuso. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ubuso buyaziwa. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uqhubeke."</string>
@@ -244,8 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Umsindo"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ihedisethi"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Okokufaka"</string>
- <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
- <skip />
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Imishini yendlebe"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Iyavula..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
@@ -1006,8 +1004,7 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ayikwazi ukulondoloza. Zama futhi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ayikwazi ukulondoloza."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Sebenzisa okungenani izinhlamvu ezi-4"</string>
- <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
- <skip />
+ <string name="media_output_broadcast_edit_hint_no_more_than_max" msgid="3923625800037673922">"Sebenzisa isinhlamvu ezimbalwa kuneziyi-<xliff:g id="LENGTH">%1$d</xliff:g>"</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>
<string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
@@ -1049,6 +1046,8 @@
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kube khona inkinga ngokufunda imitha yakho yebhethri"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Thepha ukuze uthole olunye ulwazi"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Akukho alamu esethiwe"</string>
+ <!-- no translation found for accessibility_bouncer (5896923685673320070) -->
+ <skip />
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Inzwa yesigxivizo somunwe"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"gunyaza"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"faka idivayisi"</string>
@@ -1128,12 +1127,12 @@
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Funda kabanzi"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Funda kabanzi ku-<xliff:g id="URL">%s</xliff:g>"</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Vula i-<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• I-app isethiwe"</string>
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Okungenani ikhadi elilodwa lengeziwe ku-Wallet"</string>
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Faka i-app yekhamera"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• I-app isethiwe"</string>
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Okungenani idivayisi eyodwa iyatholakala"</string>
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction" msgid="2274489846095284167">"Khetha i-app yamanothi azenzakalelayo ukuze usebenzise isinqamuleli sokubhala amanothi"</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Ukuze ungeze i-app ye-Wallet njengesinqamuleli, qinisekisa ukuthi i-app ifakiwe"</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Ukuze ungeze i-app ye-Wallet njengesinqamuleli, qinisekisa ukuthi okungenani ikhadi elilodwa lingeziwe"</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation" msgid="3049582306241150946">"Ukuze ungeze Iskena sekhodi ye-QR njengesinqamuleli, qinisekisa ukuthi i-app yekhamera ifakiwe"</string>
+ <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Ukuze ungeze i-App yasekhaya njengesinqamuleli, qinisekisa ukuthi i-app ifakiwe"</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app" msgid="7953595390775156839">"• Okungenani idivayisi eyodwa iyatholakala"</string>
+ <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Khetha i-app yamanothi azenzakalelayo ukuze usebenzise isinqamuleli sokubhala amanothi"</string>
<string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Khetha i-app"</string>
<string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Thinta futhi ubambe isinqamuleli"</string>
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Khansela"</string>
@@ -1162,4 +1161,5 @@
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imodi ebalulekile ivuliwe"</string>
<string name="assistant_attention_content_description" msgid="6830215897604642875">"Ukunaka kwe-Assistant kuvuliwe"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
+ <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index d651a21..134a7a9 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -211,4 +211,6 @@
<item type="id" name="keyguard_indication_area" />
<item type="id" name="keyguard_indication_text" />
<item type="id" name="keyguard_indication_text_bottom" />
+ <item type="id" name="lock_icon" />
+ <item type="id" name="lock_icon_bg" />
</resources>
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
index 38c1640..c167256 100644
--- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -16,12 +16,14 @@
-->
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
android:id="@+id/header_transition"
app:constraintSetEnd="@id/qs_header_constraint"
- app:constraintSetStart="@id/qqs_header_constraint">
+ app:constraintSetStart="@id/qqs_header_constraint"
+ motion:layoutDuringTransition="honorRequest">
<KeyFrameSet>
<!-- These positions are to prevent visual movement of @id/date -->
<KeyPosition
@@ -51,56 +53,28 @@
android:alpha="0"
/>
<KeyPosition
+ app:motionTarget="@id/shade_header_system_icons"
app:keyPositionType="deltaRelative"
app:percentX="0"
app:percentY="@dimen/percent_displacement_at_fade_out"
app:framePosition="@integer/fade_out_complete_frame"
app:sizePercent="0"
- app:curveFit="linear"
- app:motionTarget="@id/statusIcons" />
+ app:curveFit="linear" />
<KeyPosition
+ app:motionTarget="@id/shade_header_system_icons"
app:keyPositionType="deltaRelative"
app:percentX="1"
app:percentY="0.5"
app:framePosition="50"
app:sizePercent="1"
- app:curveFit="linear"
- app:motionTarget="@id/statusIcons" />
+ app:curveFit="linear" />
<KeyAttribute
- app:motionTarget="@id/statusIcons"
+ app:motionTarget="@id/shade_header_system_icons"
app:framePosition="@integer/fade_out_complete_frame"
android:alpha="0"
/>
<KeyAttribute
- app:motionTarget="@id/statusIcons"
- app:framePosition="@integer/fade_in_start_frame"
- android:alpha="0"
- />
- <KeyPosition
- app:keyPositionType="deltaRelative"
- app:percentX="0"
- app:percentY="@dimen/percent_displacement_at_fade_out"
- app:framePosition="@integer/fade_out_complete_frame"
- app:percentWidth="1"
- app:percentHeight="1"
- app:curveFit="linear"
- app:motionTarget="@id/batteryRemainingIcon" />
- <KeyPosition
- app:keyPositionType="deltaRelative"
- app:percentX="1"
- app:percentY="0.5"
- app:framePosition="50"
- app:percentWidth="1"
- app:percentHeight="1"
- app:curveFit="linear"
- app:motionTarget="@id/batteryRemainingIcon" />
- <KeyAttribute
- app:motionTarget="@id/batteryRemainingIcon"
- app:framePosition="@integer/fade_out_complete_frame"
- android:alpha="0"
- />
- <KeyAttribute
- app:motionTarget="@id/batteryRemainingIcon"
+ app:motionTarget="@id/shade_header_system_icons"
app:framePosition="@integer/fade_in_start_frame"
android:alpha="0"
/>
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index bf576dc..39f4c81 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -45,7 +45,7 @@
android:layout_height="0dp"
android:layout_gravity="end|center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
+ app:layout_constraintEnd_toStartOf="@id/shade_header_system_icons"
app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="wrap"
@@ -53,28 +53,17 @@
<PropertySet android:alpha="1" />
</Constraint>
- <Constraint android:id="@+id/statusIcons">
+ <Constraint android:id="@+id/shade_header_system_icons">
<Layout
android:layout_width="wrap_content"
android:layout_height="@dimen/large_screen_shade_header_min_height"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
+ app:layout_constraintEnd_toStartOf="@id/privacy_container"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="@id/carrier_group"/>
<PropertySet android:alpha="1" />
</Constraint>
- <Constraint android:id="@+id/batteryRemainingIcon">
- <Layout
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@id/privacy_container"
- app:layout_constraintTop_toTopOf="parent" />
- <PropertySet android:alpha="1" />
- </Constraint>
-
<Constraint android:id="@+id/privacy_container">
<Layout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index 1950965..50a388d 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -54,27 +54,12 @@
</Constraint>
<Constraint
- android:id="@+id/statusIcons">
+ android:id="@+id/shade_header_system_icons">
<Layout
android:layout_width="wrap_content"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintHorizontal_chainStyle="packed"
- />
- </Constraint>
-
- <Constraint
- android:id="@+id/batteryRemainingIcon">
- <Layout
- android:layout_width="wrap_content"
- android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
app:layout_constraintEnd_toEndOf="@id/end_guide"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index 8039c68..7b4282f 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -59,7 +59,7 @@
/>
</Constraint>
- <!-- LargeScreenShadeHeaderController helps with managing clock width to layout this view -->
+ <!-- ShadeHeaderController helps with managing clock width to layout this view -->
<Constraint
android:id="@+id/carrier_group">
<Layout
@@ -78,25 +78,11 @@
</Constraint>
<Constraint
- android:id="@+id/statusIcons">
+ android:id="@+id/shade_header_system_icons">
<Layout
android:layout_width="0dp"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
app:layout_constraintWidth_default="wrap"
- app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
- app:layout_constraintTop_toTopOf="@id/date"
- app:layout_constraintBottom_toBottomOf="@id/date"
- />
- </Constraint>
-
- <Constraint
- android:id="@+id/batteryRemainingIcon">
- <Layout
- android:layout_width="0dp"
- android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constraintWidth_default="wrap"
- app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/date"
app:layout_constraintBottom_toBottomOf="@id/date"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 751a3f8..2e6c485 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -104,7 +104,8 @@
* @return updated set of flags from InputMethodService based off {@param oldHints}
* Leaves original hints unmodified
*/
- public static int calculateBackDispositionHints(int oldHints, int backDisposition,
+ public static int calculateBackDispositionHints(int oldHints,
+ @InputMethodService.BackDispositionMode int backDisposition,
boolean imeShown, boolean showImeSwitcher) {
int hints = oldHints;
switch (backDisposition) {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index a724514..b52ee01 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -148,7 +148,8 @@
/**
* The status of this lock screen. Primarily used for widgets on LockScreen.
*/
- private enum StatusMode {
+ @VisibleForTesting
+ protected enum StatusMode {
Normal, // Normal case (sim card present, it's not locked)
NetworkLocked, // SIM card is 'network locked'.
SimMissing, // SIM card is missing.
@@ -158,6 +159,7 @@
SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
SimIoError, // SIM card is faulty
+ SimRestricted, // SIM Card restricted, present but not usable due to carrier restrictions.
SimUnknown // SIM card is unknown
}
@@ -493,6 +495,7 @@
getContext().getText(R.string.keyguard_sim_error_message_short),
text);
break;
+ case SimRestricted: // fall through
case SimUnknown:
carrierText = null;
break;
@@ -535,19 +538,19 @@
/**
* Determine the current status of the lock screen given the SIM state and other stuff.
*/
- private CarrierTextManager.StatusMode getStatusForIccState(int simState) {
- final boolean missingAndNotProvisioned =
- !mKeyguardUpdateMonitor.isDeviceProvisioned()
- && (simState == TelephonyManager.SIM_STATE_ABSENT
- || simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
+ @VisibleForTesting
+ protected CarrierTextManager.StatusMode getStatusForIccState(int simState) {
+ if (!mKeyguardUpdateMonitor.isDeviceProvisioned()
+ && (simState == TelephonyManager.SIM_STATE_ABSENT
+ || simState == TelephonyManager.SIM_STATE_PERM_DISABLED)) {
+ return CarrierTextManager.StatusMode.SimMissingLocked;
+ }
- // Assume we're NETWORK_LOCKED if not provisioned
- simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState;
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return CarrierTextManager.StatusMode.SimMissing;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
- return CarrierTextManager.StatusMode.SimMissingLocked;
+ return CarrierTextManager.StatusMode.NetworkLocked;
case TelephonyManager.SIM_STATE_NOT_READY:
return CarrierTextManager.StatusMode.SimNotReady;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
@@ -562,6 +565,8 @@
return CarrierTextManager.StatusMode.SimUnknown;
case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
return CarrierTextManager.StatusMode.SimIoError;
+ case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
+ return CarrierTextManager.StatusMode.SimRestricted;
}
return CarrierTextManager.StatusMode.SimUnknown;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 7acfbf6..bb11217 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -53,6 +53,7 @@
private boolean mDismissing;
protected AsyncTask<?, ?, ?> mPendingLockCheck;
protected boolean mResumed;
+ protected boolean mLockedOut;
private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> {
// Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
@@ -137,6 +138,8 @@
// Prevent user from using the PIN/Password entry until scheduled deadline.
protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
mView.setPasswordEntryEnabled(false);
+ mView.setPasswordEntryInputEnabled(false);
+ mLockedOut = true;
long elapsedRealtime = SystemClock.elapsedRealtime();
long secondsInFuture = (long) Math.ceil(
(elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
@@ -159,6 +162,7 @@
@Override
public void onFinish() {
mMessageAreaController.setMessage("");
+ mLockedOut = false;
resetState();
}
}.start();
@@ -194,6 +198,7 @@
protected void verifyPasswordAndUnlock() {
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
+ if (mLockedOut) return;
final LockscreenCredential password = mView.getEnteredCredential();
mView.setPasswordEntryInputEnabled(false);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 1d7c35d..03d9eb3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -23,6 +23,7 @@
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
@@ -99,14 +100,16 @@
switch (reason) {
case PROMPT_REASON_RESTART:
return R.string.kg_prompt_reason_restart_password;
+ case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE:
+ return R.string.kg_prompt_after_update_password;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_password;
case PROMPT_REASON_DEVICE_ADMIN:
return R.string.kg_prompt_reason_device_admin;
case PROMPT_REASON_USER_REQUEST:
- return R.string.kg_prompt_reason_user_request;
+ return R.string.kg_prompt_after_user_lockdown_password;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
- return R.string.kg_prompt_reason_timeout_password;
+ return R.string.kg_prompt_unattended_update_password;
case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
return R.string.kg_prompt_reason_timeout_password;
case PROMPT_REASON_TRUSTAGENT_EXPIRED:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index bcf8e98..49f788c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -236,6 +236,7 @@
getKeyguardSecurityCallback().onCancelClicked();
});
}
+ mView.onDevicePostureChanged(mPostureController.getDevicePosture());
mPostureController.addCallback(mPostureCallback);
}
@@ -304,6 +305,9 @@
case PROMPT_REASON_RESTART:
resId = R.string.kg_prompt_reason_restart_pattern;
break;
+ case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE:
+ resId = R.string.kg_prompt_after_update_pattern;
+ break;
case PROMPT_REASON_TIMEOUT:
resId = R.string.kg_prompt_reason_timeout_pattern;
break;
@@ -311,10 +315,10 @@
resId = R.string.kg_prompt_reason_device_admin;
break;
case PROMPT_REASON_USER_REQUEST:
- resId = R.string.kg_prompt_reason_user_request;
+ resId = R.string.kg_prompt_after_user_lockdown_pattern;
break;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
- resId = R.string.kg_prompt_reason_timeout_pattern;
+ resId = R.string.kg_prompt_unattended_update_pattern;
break;
case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
resId = R.string.kg_prompt_reason_timeout_pattern;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 5cb2c5c..38e5dc5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -21,6 +21,7 @@
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
@@ -113,14 +114,16 @@
switch (reason) {
case PROMPT_REASON_RESTART:
return R.string.kg_prompt_reason_restart_pin;
+ case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE:
+ return R.string.kg_prompt_after_update_pin;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_pin;
case PROMPT_REASON_DEVICE_ADMIN:
return R.string.kg_prompt_reason_device_admin;
case PROMPT_REASON_USER_REQUEST:
- return R.string.kg_prompt_reason_user_request;
+ return R.string.kg_prompt_after_user_lockdown_pin;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
- return R.string.kg_prompt_reason_timeout_pin;
+ return R.string.kg_prompt_unattended_update_pin;
case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
return R.string.kg_prompt_reason_timeout_pin;
case PROMPT_REASON_TRUSTAGENT_EXPIRED:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 4211f55..841b5b3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -474,7 +474,8 @@
return false;
}
// Avoid dragging the pattern view
- if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) {
+ if (mSecurityViewFlipper.getSecurityView() != null
+ && mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) {
return false;
}
int index = event.findPointerIndex(mActivePointerId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 419303d..21960e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -103,6 +103,12 @@
int PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT = 15;
/**
+ * Strong auth is required because the device has just booted because of an automatic
+ * mainline update.
+ */
+ int PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE = 16;
+
+ /**
* Reset the view and prepare to take input. This should do things like clearing the
* password or pattern and clear error messages.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 64ab758..90401cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2033,11 +2033,47 @@
private final HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
/**
- * When we receive a
- * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
+ * When we receive a {@link android.content.Intent#ACTION_SIM_STATE_CHANGED} broadcast,
* and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
* we need a single object to pass to the handler. This class helps decode
* the intent and provide a {@link SimData} result.
+ *
+ * Below is the Sim state mapping matrixs:
+ * +---+-----------------------------------------------------+----------------------------+
+ * | |Telephony FWK broadcast with action |SystemUI mapping SIM state |
+ * | |android.content.Intent#ACTION_SIM_STATE_CHANGED |refer to android.telephony. |
+ * |NO.+-------------------------+---------------------------+TelephonyManager#getSimState|
+ * | |EXTRA_SIM_STATE |EXTRA_SIM_LOCKED_REASON | |
+ * | |(Intent#XXX) |(Intent#XXX) |TelephonyManager#SimState |
+ * +===+=====================================================+============================+
+ * |1 |SIM_STATE_UNKNOWN |always null |SIM_STATE_UNKNOWN |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |2 |SIM_STATE_ABSENT |always null |SIM_STATE_ABSENT |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |3 |SIM_STATE_CARD_IO_ERROR |SIM_STATE_CARD_IO_ERROR |SIM_STATE_CARD_IO_ERROR |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |4 |SIM_STATE_CARD_RESTRICTED|SIM_STATE_CARD_RESTRICTED |SIM_STATE_CARD_RESTRICTED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |5 |SIM_STATE_LOCKED |SIM_LOCKED_ON_PIN |SIM_STATE_PIN_REQUIRED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |6 |SIM_STATE_LOCKED |SIM_LOCKED_ON_PUK |SIM_STATE_PUK_REQUIRED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |7 |SIM_STATE_LOCKED |SIM_LOCKED_NETWORK |SIM_STATE_NETWORK_LOCKED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |8 |SIM_STATE_LOCKED |SIM_ABSENT_ON_PERM_DISABLED|SIM_STATE_PERM_DISABLED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |9 |SIM_STATE_NOT_READY |always null |SIM_STATE_NOT_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |10 |SIM_STATE_IMSI |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |11 |SIM_STATE_READY |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |12 |SIM_STATE_LOADED |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ *
+ * Note that, it seems #10 imsi ready case(i.e. SIM_STATE_IMSI) is never triggered from
+ * Android Pie(telephony FWK doesn't trigger this broadcast any more), but it is still
+ * OK keep this mapping logic.
*/
private static class SimData {
public int simState;
@@ -2051,26 +2087,16 @@
}
static SimData fromIntent(Intent intent) {
- int state;
if (!Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
}
+ int state = TelephonyManager.SIM_STATE_UNKNOWN;
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
- final String absentReason = intent
- .getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
-
- if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(
- absentReason)) {
- state = TelephonyManager.SIM_STATE_PERM_DISABLED;
- } else {
- state = TelephonyManager.SIM_STATE_ABSENT;
- }
- } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
- state = TelephonyManager.SIM_STATE_READY;
+ state = TelephonyManager.SIM_STATE_ABSENT;
} else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
final String lockedReason = intent
.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
@@ -2078,22 +2104,24 @@
state = TelephonyManager.SIM_STATE_PIN_REQUIRED;
} else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
state = TelephonyManager.SIM_STATE_PUK_REQUIRED;
+ } else if (Intent.SIM_LOCKED_NETWORK.equals(lockedReason)) {
+ state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
} else if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(lockedReason)) {
state = TelephonyManager.SIM_STATE_PERM_DISABLED;
- } else {
- state = TelephonyManager.SIM_STATE_UNKNOWN;
}
- } else if (Intent.SIM_LOCKED_NETWORK.equals(stateExtra)) {
- state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
} else if (Intent.SIM_STATE_CARD_IO_ERROR.equals(stateExtra)) {
state = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
- } else if (Intent.SIM_STATE_LOADED.equals(stateExtra)
+ } else if (Intent.SIM_STATE_CARD_RESTRICTED.equals(stateExtra)) {
+ state = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
+ } else if (Intent.SIM_STATE_NOT_READY.equals(stateExtra)) {
+ state = TelephonyManager.SIM_STATE_NOT_READY;
+ } else if (Intent.SIM_STATE_READY.equals(stateExtra)
+ || Intent.SIM_STATE_LOADED.equals(stateExtra)
|| Intent.SIM_STATE_IMSI.equals(stateExtra)) {
- // This is required because telephony doesn't return to "READY" after
+ // Mapping SIM_STATE_LOADED and SIM_STATE_IMSI to SIM_STATE_READY is required
+ // because telephony doesn't return to "READY" after
// these state transitions. See bug 7197471.
state = TelephonyManager.SIM_STATE_READY;
- } else {
- state = TelephonyManager.SIM_STATE_UNKNOWN;
}
return new SimData(state, slotId, subId);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 281067d..bc12aee 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -119,6 +119,14 @@
boolean isUnlockWithWallpaper();
/**
+ * @return Whether the bouncer over dream is showing. Note that the bouncer over dream is
+ * handled independently of the rest of the notification panel. As a result, setting this state
+ * via {@link CentralSurfaces#setBouncerShowing(boolean)} leads to unintended side effects from
+ * states modified behind the dream.
+ */
+ boolean isBouncerShowingOverDream();
+
+ /**
* @return Whether subtle animation should be used for unlocking the device.
*/
boolean shouldSubtleWindowAnimationsForUnlock();
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index abad0be..d1fffaa 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
@@ -23,6 +25,7 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -68,13 +71,9 @@
public LockIconView(Context context, AttributeSet attrs) {
super(context, attrs);
mSensorRect = new RectF();
- }
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
- mLockIcon = findViewById(R.id.lock_icon);
- mBgView = findViewById(R.id.lock_icon_bg);
+ addBgImageView(context, attrs);
+ addLockIconImageView(context, attrs);
}
void setDozeAmount(float dozeAmount) {
@@ -184,6 +183,30 @@
mLockIcon.setImageState(getLockIconState(mIconType, mAod), true);
}
+ private void addLockIconImageView(Context context, AttributeSet attrs) {
+ mLockIcon = new ImageView(context, attrs);
+ mLockIcon.setId(R.id.lock_icon);
+ mLockIcon.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ addView(mLockIcon);
+ LayoutParams lp = (LayoutParams) mLockIcon.getLayoutParams();
+ lp.height = MATCH_PARENT;
+ lp.width = MATCH_PARENT;
+ lp.gravity = Gravity.CENTER;
+ mLockIcon.setLayoutParams(lp);
+ }
+
+ private void addBgImageView(Context context, AttributeSet attrs) {
+ mBgView = new ImageView(context, attrs);
+ mBgView.setId(R.id.lock_icon_bg);
+ mBgView.setImageDrawable(context.getDrawable(R.drawable.fingerprint_bg));
+ mBgView.setVisibility(View.INVISIBLE);
+ addView(mBgView);
+ LayoutParams lp = (LayoutParams) mBgView.getLayoutParams();
+ lp.height = MATCH_PARENT;
+ lp.width = MATCH_PARENT;
+ mBgView.setLayoutParams(lp);
+ }
+
private static int[] getLockIconState(@IconType int icon, boolean aod) {
if (icon == ICON_NONE) {
return new int[0];
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
deleted file mode 100644
index 7517dee..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
+++ /dev/null
@@ -1,210 +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.keyguard.clock;
-
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Paint.Style;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextClock;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.ClockPlugin;
-
-import java.util.TimeZone;
-
-/**
- * Controller for Stretch clock that can appear on lock screen and AOD.
- */
-public class AnalogClockController implements ClockPlugin {
-
- /**
- * Resources used to get title and thumbnail.
- */
- private final Resources mResources;
-
- /**
- * LayoutInflater used to inflate custom clock views.
- */
- private final LayoutInflater mLayoutInflater;
-
- /**
- * Extracts accent color from wallpaper.
- */
- private final SysuiColorExtractor mColorExtractor;
-
- /**
- * Computes preferred position of clock.
- */
- private final SmallClockPosition mClockPosition;
-
- /**
- * Renders preview from clock view.
- */
- private final ViewPreviewer mRenderer = new ViewPreviewer();
-
- /**
- * Custom clock shown on AOD screen and behind stack scroller on lock.
- */
- private ClockLayout mBigClockView;
- private ImageClock mAnalogClock;
-
- /**
- * Small clock shown on lock screen above stack scroller.
- */
- private View mView;
- private TextClock mLockClock;
-
- /**
- * Helper to extract colors from wallpaper palette for clock face.
- */
- private final ClockPalette mPalette = new ClockPalette();
-
- /**
- * Create a BubbleClockController instance.
- *
- * @param res Resources contains title and thumbnail.
- * @param inflater Inflater used to inflate custom clock views.
- * @param colorExtractor Extracts accent color from wallpaper.
- */
- public AnalogClockController(Resources res, LayoutInflater inflater,
- SysuiColorExtractor colorExtractor) {
- mResources = res;
- mLayoutInflater = inflater;
- mColorExtractor = colorExtractor;
- mClockPosition = new SmallClockPosition(inflater.getContext());
- }
-
- private void createViews() {
- mBigClockView = (ClockLayout) mLayoutInflater.inflate(R.layout.analog_clock, null);
- mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
-
- mView = mLayoutInflater.inflate(R.layout.digital_clock, null);
- mLockClock = mView.findViewById(R.id.lock_screen_clock);
- }
-
- @Override
- public void onDestroyView() {
- mBigClockView = null;
- mAnalogClock = null;
- mView = null;
- mLockClock = null;
- }
-
- @Override
- public String getName() {
- return "analog";
- }
-
- @Override
- public String getTitle() {
- return mResources.getString(R.string.clock_title_analog);
- }
-
- @Override
- public Bitmap getThumbnail() {
- return BitmapFactory.decodeResource(mResources, R.drawable.analog_thumbnail);
- }
-
- @Override
- public Bitmap getPreview(int width, int height) {
-
- // Use the big clock view for the preview
- View view = getBigClockView();
-
- // Initialize state of plugin before generating preview.
- setDarkAmount(1f);
- setTextColor(Color.WHITE);
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK);
- setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
- onTimeTick();
-
- return mRenderer.createPreview(view, width, height);
- }
-
- @Override
- public View getView() {
- if (mView == null) {
- createViews();
- }
- return mView;
- }
-
- @Override
- public View getBigClockView() {
- if (mBigClockView == null) {
- createViews();
- }
- return mBigClockView;
- }
-
- @Override
- public int getPreferredY(int totalHeight) {
- return mClockPosition.getPreferredY();
- }
-
- @Override
- public void setStyle(Style style) {}
-
- @Override
- public void setTextColor(int color) {
- updateColor();
- }
-
- @Override
- public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
- mPalette.setColorPalette(supportsDarkText, colorPalette);
- updateColor();
- }
-
- private void updateColor() {
- final int primary = mPalette.getPrimaryColor();
- final int secondary = mPalette.getSecondaryColor();
- mLockClock.setTextColor(secondary);
- mAnalogClock.setClockColors(primary, secondary);
- }
-
- @Override
- public void onTimeTick() {
- mAnalogClock.onTimeChanged();
- mBigClockView.onTimeChanged();
- mLockClock.refreshTime();
- }
-
- @Override
- public void setDarkAmount(float darkAmount) {
- mPalette.setDarkAmount(darkAmount);
- mClockPosition.setDarkAmount(darkAmount);
- mBigClockView.setDarkAmount(darkAmount);
- }
-
- @Override
- public void onTimeZoneChanged(TimeZone timeZone) {
- mAnalogClock.onTimeZoneChanged(timeZone);
- }
-
- @Override
- public boolean shouldShowStatusArea() {
- return true;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
deleted file mode 100644
index 1add1a3..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ /dev/null
@@ -1,210 +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.keyguard.clock;
-
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Paint.Style;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextClock;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.ClockPlugin;
-
-import java.util.TimeZone;
-
-/**
- * Controller for Bubble clock that can appear on lock screen and AOD.
- */
-public class BubbleClockController implements ClockPlugin {
-
- /**
- * Resources used to get title and thumbnail.
- */
- private final Resources mResources;
-
- /**
- * LayoutInflater used to inflate custom clock views.
- */
- private final LayoutInflater mLayoutInflater;
-
- /**
- * Extracts accent color from wallpaper.
- */
- private final SysuiColorExtractor mColorExtractor;
-
- /**
- * Computes preferred position of clock.
- */
- private final SmallClockPosition mClockPosition;
-
- /**
- * Renders preview from clock view.
- */
- private final ViewPreviewer mRenderer = new ViewPreviewer();
-
- /**
- * Custom clock shown on AOD screen and behind stack scroller on lock.
- */
- private ClockLayout mView;
- private ImageClock mAnalogClock;
-
- /**
- * Small clock shown on lock screen above stack scroller.
- */
- private View mLockClockContainer;
- private TextClock mLockClock;
-
- /**
- * Helper to extract colors from wallpaper palette for clock face.
- */
- private final ClockPalette mPalette = new ClockPalette();
-
- /**
- * Create a BubbleClockController instance.
- *
- * @param res Resources contains title and thumbnail.
- * @param inflater Inflater used to inflate custom clock views.
- * @param colorExtractor Extracts accent color from wallpaper.
- */
- public BubbleClockController(Resources res, LayoutInflater inflater,
- SysuiColorExtractor colorExtractor) {
- mResources = res;
- mLayoutInflater = inflater;
- mColorExtractor = colorExtractor;
- mClockPosition = new SmallClockPosition(inflater.getContext());
- }
-
- private void createViews() {
- mView = (ClockLayout) mLayoutInflater.inflate(R.layout.bubble_clock, null);
- mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
-
- mLockClockContainer = mLayoutInflater.inflate(R.layout.digital_clock, null);
- mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock);
- }
-
- @Override
- public void onDestroyView() {
- mView = null;
- mAnalogClock = null;
- mLockClockContainer = null;
- mLockClock = null;
- }
-
- @Override
- public String getName() {
- return "bubble";
- }
-
- @Override
- public String getTitle() {
- return mResources.getString(R.string.clock_title_bubble);
- }
-
- @Override
- public Bitmap getThumbnail() {
- return BitmapFactory.decodeResource(mResources, R.drawable.bubble_thumbnail);
- }
-
- @Override
- public Bitmap getPreview(int width, int height) {
-
- // Use the big clock view for the preview
- View view = getBigClockView();
-
- // Initialize state of plugin before generating preview.
- setDarkAmount(1f);
- setTextColor(Color.WHITE);
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK);
- setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
- onTimeTick();
-
- return mRenderer.createPreview(view, width, height);
- }
-
- @Override
- public View getView() {
- if (mLockClockContainer == null) {
- createViews();
- }
- return mLockClockContainer;
- }
-
- @Override
- public View getBigClockView() {
- if (mView == null) {
- createViews();
- }
- return mView;
- }
-
- @Override
- public int getPreferredY(int totalHeight) {
- return mClockPosition.getPreferredY();
- }
-
- @Override
- public void setStyle(Style style) {}
-
- @Override
- public void setTextColor(int color) {
- updateColor();
- }
-
- @Override
- public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
- mPalette.setColorPalette(supportsDarkText, colorPalette);
- updateColor();
- }
-
- private void updateColor() {
- final int primary = mPalette.getPrimaryColor();
- final int secondary = mPalette.getSecondaryColor();
- mLockClock.setTextColor(secondary);
- mAnalogClock.setClockColors(primary, secondary);
- }
-
- @Override
- public void setDarkAmount(float darkAmount) {
- mPalette.setDarkAmount(darkAmount);
- mClockPosition.setDarkAmount(darkAmount);
- mView.setDarkAmount(darkAmount);
- }
-
- @Override
- public void onTimeTick() {
- mAnalogClock.onTimeChanged();
- mView.onTimeChanged();
- mLockClock.refreshTime();
- }
-
- @Override
- public void onTimeZoneChanged(TimeZone timeZone) {
- mAnalogClock.onTimeZoneChanged(timeZone);
- }
-
- @Override
- public boolean shouldShowStatusArea() {
- return true;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
deleted file mode 100644
index 0210e08..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
+++ /dev/null
@@ -1,117 +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.keyguard.clock;
-
-import android.graphics.Bitmap;
-
-import java.util.function.Supplier;
-
-/**
- * Metadata about an available clock face.
- */
-final class ClockInfo {
-
- private final String mName;
- private final Supplier<String> mTitle;
- private final String mId;
- private final Supplier<Bitmap> mThumbnail;
- private final Supplier<Bitmap> mPreview;
-
- private ClockInfo(String name, Supplier<String> title, String id,
- Supplier<Bitmap> thumbnail, Supplier<Bitmap> preview) {
- mName = name;
- mTitle = title;
- mId = id;
- mThumbnail = thumbnail;
- mPreview = preview;
- }
-
- /**
- * Gets the non-internationalized name for the clock face.
- */
- String getName() {
- return mName;
- }
-
- /**
- * Gets the name (title) of the clock face to be shown in the picker app.
- */
- String getTitle() {
- return mTitle.get();
- }
-
- /**
- * Gets the ID of the clock face, used by the picker to set the current selection.
- */
- String getId() {
- return mId;
- }
-
- /**
- * Gets a thumbnail image of the clock.
- */
- Bitmap getThumbnail() {
- return mThumbnail.get();
- }
-
- /**
- * Gets a potentially realistic preview image of the clock face.
- */
- Bitmap getPreview() {
- return mPreview.get();
- }
-
- static Builder builder() {
- return new Builder();
- }
-
- static class Builder {
- private String mName;
- private Supplier<String> mTitle;
- private String mId;
- private Supplier<Bitmap> mThumbnail;
- private Supplier<Bitmap> mPreview;
-
- public ClockInfo build() {
- return new ClockInfo(mName, mTitle, mId, mThumbnail, mPreview);
- }
-
- public Builder setName(String name) {
- mName = name;
- return this;
- }
-
- public Builder setTitle(Supplier<String> title) {
- mTitle = title;
- return this;
- }
-
- public Builder setId(String id) {
- mId = id;
- return this;
- }
-
- public Builder setThumbnail(Supplier<Bitmap> thumbnail) {
- mThumbnail = thumbnail;
- return this;
- }
-
- public Builder setPreview(Supplier<Bitmap> preview) {
- mPreview = preview;
- return this;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfoModule.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfoModule.java
deleted file mode 100644
index 72a44bd..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfoModule.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.keyguard.clock;
-
-import java.util.List;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * Dagger Module for clock package.
- *
- * @deprecated Migrate to ClockRegistry
- */
-@Module
-@Deprecated
-public abstract class ClockInfoModule {
-
- /** */
- @Provides
- public static List<ClockInfo> provideClockInfoList(ClockManager clockManager) {
- return clockManager.getClockInfos();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
deleted file mode 100644
index d44d89e..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ /dev/null
@@ -1,109 +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.keyguard.clock;
-
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.util.MathUtils;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- * Positions clock faces (analog, digital, typographic) and handles pixel shifting
- * to prevent screen burn-in.
- */
-public class ClockLayout extends FrameLayout {
-
- private static final int ANALOG_CLOCK_SHIFT_FACTOR = 3;
- /**
- * Clock face views.
- */
- private View mAnalogClock;
-
- /**
- * Pixel shifting amplitudes used to prevent screen burn-in.
- */
- private int mBurnInPreventionOffsetX;
- private int mBurnInPreventionOffsetY;
-
- private float mDarkAmount;
-
- public ClockLayout(Context context) {
- this(context, null);
- }
-
- public ClockLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ClockLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mAnalogClock = findViewById(R.id.analog_clock);
-
- // Get pixel shifting X, Y amplitudes from resources.
- Resources resources = getResources();
- mBurnInPreventionOffsetX = resources.getDimensionPixelSize(
- R.dimen.burn_in_prevention_offset_x);
- mBurnInPreventionOffsetY = resources.getDimensionPixelSize(
- R.dimen.burn_in_prevention_offset_y);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- positionChildren();
- }
-
- void onTimeChanged() {
- positionChildren();
- }
-
- /**
- * See {@link com.android.systemui.plugins.ClockPlugin#setDarkAmount(float)}.
- */
- void setDarkAmount(float darkAmount) {
- mDarkAmount = darkAmount;
- positionChildren();
- }
-
- private void positionChildren() {
- final float offsetX = MathUtils.lerp(0f,
- getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - mBurnInPreventionOffsetX,
- mDarkAmount);
- final float offsetY = MathUtils.lerp(0f,
- getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
- - 0.5f * mBurnInPreventionOffsetY,
- mDarkAmount);
-
- // Put the analog clock in the middle of the screen.
- if (mAnalogClock != null) {
- mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
- + ANALOG_CLOCK_SHIFT_FACTOR * offsetX);
- mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
- + ANALOG_CLOCK_SHIFT_FACTOR * offsetY);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
deleted file mode 100644
index 122c521..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ /dev/null
@@ -1,392 +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.keyguard.clock;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArrayMap;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dock.DockManager.DockEventListener;
-import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.settings.UserTracker;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Supplier;
-
-import javax.inject.Inject;
-
-/**
- * Manages custom clock faces for AOD and lock screen.
- *
- * @deprecated Migrate to ClockRegistry
- */
-@SysUISingleton
-@Deprecated
-public final class ClockManager {
-
- private static final String TAG = "ClockOptsProvider";
-
- private final AvailableClocks mPreviewClocks;
- private final List<Supplier<ClockPlugin>> mBuiltinClocks = new ArrayList<>();
-
- private final Context mContext;
- private final ContentResolver mContentResolver;
- private final SettingsWrapper mSettingsWrapper;
- private final Handler mMainHandler = new Handler(Looper.getMainLooper());
- private final UserTracker mUserTracker;
- private final Executor mMainExecutor;
-
- /**
- * Observe settings changes to know when to switch the clock face.
- */
- private final ContentObserver mContentObserver =
- new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange, Collection<Uri> uris,
- int flags, int userId) {
- if (Objects.equals(userId,
- mUserTracker.getUserId())) {
- reload();
- }
- }
- };
-
- /**
- * Observe user changes and react by potentially loading the custom clock for the new user.
- */
- private final UserTracker.Callback mUserChangedCallback =
- new UserTracker.Callback() {
- @Override
- public void onUserChanged(int newUser, @NonNull Context userContext) {
- reload();
- }
- };
-
- private final PluginManager mPluginManager;
- @Nullable private final DockManager mDockManager;
-
- /**
- * Observe changes to dock state to know when to switch the clock face.
- */
- private final DockEventListener mDockEventListener =
- new DockEventListener() {
- @Override
- public void onEvent(int event) {
- mIsDocked = (event == DockManager.STATE_DOCKED
- || event == DockManager.STATE_DOCKED_HIDE);
- reload();
- }
- };
-
- /**
- * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face
- * to show.
- */
- private boolean mIsDocked;
-
- /**
- * Listeners for onClockChanged event.
- *
- * Each listener must receive a separate clock plugin instance. Otherwise, there could be
- * problems like attempting to attach a view that already has a parent. To deal with this issue,
- * each listener is associated with a collection of available clocks. When onClockChanged is
- * fired the current clock plugin instance is retrieved from that listeners available clocks.
- */
- private final Map<ClockChangedListener, AvailableClocks> mListeners = new ArrayMap<>();
-
- private final int mWidth;
- private final int mHeight;
-
- @Inject
- public ClockManager(Context context, LayoutInflater layoutInflater,
- PluginManager pluginManager, SysuiColorExtractor colorExtractor,
- @Nullable DockManager dockManager, UserTracker userTracker,
- @Main Executor mainExecutor) {
- this(context, layoutInflater, pluginManager, colorExtractor,
- context.getContentResolver(), userTracker, mainExecutor,
- new SettingsWrapper(context.getContentResolver()), dockManager);
- }
-
- @VisibleForTesting
- ClockManager(Context context, LayoutInflater layoutInflater,
- PluginManager pluginManager, SysuiColorExtractor colorExtractor,
- ContentResolver contentResolver, UserTracker userTracker, Executor mainExecutor,
- SettingsWrapper settingsWrapper, DockManager dockManager) {
- mContext = context;
- mPluginManager = pluginManager;
- mContentResolver = contentResolver;
- mSettingsWrapper = settingsWrapper;
- mUserTracker = userTracker;
- mMainExecutor = mainExecutor;
- mDockManager = dockManager;
- mPreviewClocks = new AvailableClocks();
-
- Resources res = context.getResources();
-
- addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
-
- // Store the size of the display for generation of clock preview.
- DisplayMetrics dm = res.getDisplayMetrics();
- mWidth = dm.widthPixels;
- mHeight = dm.heightPixels;
- }
-
- /**
- * Add listener to be notified when clock implementation should change.
- */
- public void addOnClockChangedListener(ClockChangedListener listener) {
- if (mListeners.isEmpty()) {
- register();
- }
- AvailableClocks availableClocks = new AvailableClocks();
- for (int i = 0; i < mBuiltinClocks.size(); i++) {
- availableClocks.addClockPlugin(mBuiltinClocks.get(i).get());
- }
- mListeners.put(listener, availableClocks);
- mPluginManager.addPluginListener(availableClocks, ClockPlugin.class, true);
- reload();
- }
-
- /**
- * Remove listener added with {@link addOnClockChangedListener}.
- */
- public void removeOnClockChangedListener(ClockChangedListener listener) {
- AvailableClocks availableClocks = mListeners.remove(listener);
- mPluginManager.removePluginListener(availableClocks);
- if (mListeners.isEmpty()) {
- unregister();
- }
- }
-
- /**
- * Get information about available clock faces.
- */
- List<ClockInfo> getClockInfos() {
- return mPreviewClocks.getInfo();
- }
-
- /**
- * Get the current clock.
- * @return current custom clock or null for default.
- */
- @Nullable
- ClockPlugin getCurrentClock() {
- return mPreviewClocks.getCurrentClock();
- }
-
- @VisibleForTesting
- boolean isDocked() {
- return mIsDocked;
- }
-
- @VisibleForTesting
- ContentObserver getContentObserver() {
- return mContentObserver;
- }
-
- @VisibleForTesting
- void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
- ClockPlugin plugin = pluginSupplier.get();
- mPreviewClocks.addClockPlugin(plugin);
- mBuiltinClocks.add(pluginSupplier);
- }
-
- private void register() {
- mPluginManager.addPluginListener(mPreviewClocks, ClockPlugin.class, true);
- mContentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
- false, mContentObserver, UserHandle.USER_ALL);
- mContentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE),
- false, mContentObserver, UserHandle.USER_ALL);
- mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
- if (mDockManager != null) {
- mDockManager.addListener(mDockEventListener);
- }
- }
-
- private void unregister() {
- mPluginManager.removePluginListener(mPreviewClocks);
- mContentResolver.unregisterContentObserver(mContentObserver);
- mUserTracker.removeCallback(mUserChangedCallback);
- if (mDockManager != null) {
- mDockManager.removeListener(mDockEventListener);
- }
- }
-
- private void reload() {
- mPreviewClocks.reloadCurrentClock();
- mListeners.forEach((listener, clocks) -> {
- clocks.reloadCurrentClock();
- final ClockPlugin clock = clocks.getCurrentClock();
- if (Looper.myLooper() == Looper.getMainLooper()) {
- listener.onClockChanged(clock instanceof DefaultClockController ? null : clock);
- } else {
- mMainHandler.post(() -> listener.onClockChanged(
- clock instanceof DefaultClockController ? null : clock));
- }
- });
- }
-
- /**
- * Listener for events that should cause the custom clock face to change.
- */
- public interface ClockChangedListener {
- /**
- * Called when custom clock should change.
- *
- * @param clock Custom clock face to use. A null value indicates the default clock face.
- */
- void onClockChanged(ClockPlugin clock);
- }
-
- /**
- * Collection of available clocks.
- */
- private final class AvailableClocks implements PluginListener<ClockPlugin> {
-
- /**
- * Map from expected value stored in settings to plugin for custom clock face.
- */
- private final Map<String, ClockPlugin> mClocks = new ArrayMap<>();
-
- /**
- * Metadata about available clocks, such as name and preview images.
- */
- private final List<ClockInfo> mClockInfo = new ArrayList<>();
-
- /**
- * Active ClockPlugin.
- */
- @Nullable private ClockPlugin mCurrentClock;
-
- @Override
- public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
- addClockPlugin(plugin);
- reloadIfNeeded(plugin);
- }
-
- @Override
- public void onPluginDisconnected(ClockPlugin plugin) {
- removeClockPlugin(plugin);
- reloadIfNeeded(plugin);
- }
-
- /**
- * Get the current clock.
- * @return current custom clock or null for default.
- */
- @Nullable
- ClockPlugin getCurrentClock() {
- return mCurrentClock;
- }
-
- /**
- * Get information about available clock faces.
- */
- List<ClockInfo> getInfo() {
- return mClockInfo;
- }
-
- /**
- * Adds a clock plugin to the collection of available clocks.
- *
- * @param plugin The plugin to add.
- */
- void addClockPlugin(ClockPlugin plugin) {
- final String id = plugin.getClass().getName();
- mClocks.put(plugin.getClass().getName(), plugin);
- mClockInfo.add(ClockInfo.builder()
- .setName(plugin.getName())
- .setTitle(plugin::getTitle)
- .setId(id)
- .setThumbnail(plugin::getThumbnail)
- .setPreview(() -> plugin.getPreview(mWidth, mHeight))
- .build());
- }
-
- private void removeClockPlugin(ClockPlugin plugin) {
- final String id = plugin.getClass().getName();
- mClocks.remove(id);
- for (int i = 0; i < mClockInfo.size(); i++) {
- if (id.equals(mClockInfo.get(i).getId())) {
- mClockInfo.remove(i);
- break;
- }
- }
- }
-
- private void reloadIfNeeded(ClockPlugin plugin) {
- final boolean wasCurrentClock = plugin == mCurrentClock;
- reloadCurrentClock();
- final boolean isCurrentClock = plugin == mCurrentClock;
- if (wasCurrentClock || isCurrentClock) {
- ClockManager.this.reload();
- }
- }
-
- /**
- * Update the current clock.
- */
- void reloadCurrentClock() {
- mCurrentClock = getClockPlugin();
- }
-
- private ClockPlugin getClockPlugin() {
- ClockPlugin plugin = null;
- if (ClockManager.this.isDocked()) {
- final String name = mSettingsWrapper.getDockedClockFace(
- mUserTracker.getUserId());
- if (name != null) {
- plugin = mClocks.get(name);
- if (plugin != null) {
- return plugin;
- }
- }
- }
- final String name = mSettingsWrapper.getLockScreenCustomClockFace(
- mUserTracker.getUserId());
- if (name != null) {
- plugin = mClocks.get(name);
- }
- return plugin;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java
deleted file mode 100644
index b6413cb..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java
+++ /dev/null
@@ -1,183 +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.keyguard.clock;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileNotFoundException;
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Exposes custom clock face options and provides realistic preview images.
- *
- * APIs:
- *
- * /list_options: List the available clock faces, which has the following columns
- * name: name of the clock face
- * title: title of the clock face
- * id: value used to set the clock face
- * thumbnail: uri of the thumbnail image, should be /thumbnail/{name}
- * preview: uri of the preview image, should be /preview/{name}
- *
- * /thumbnail/{id}: Opens a file stream for the thumbnail image for clock face {id}.
- *
- * /preview/{id}: Opens a file stream for the preview image for clock face {id}.
- */
-public final class ClockOptionsProvider extends ContentProvider {
-
- private static final String TAG = "ClockOptionsProvider";
- private static final String KEY_LIST_OPTIONS = "/list_options";
- private static final String KEY_PREVIEW = "preview";
- private static final String KEY_THUMBNAIL = "thumbnail";
- private static final String COLUMN_NAME = "name";
- private static final String COLUMN_TITLE = "title";
- private static final String COLUMN_ID = "id";
- private static final String COLUMN_THUMBNAIL = "thumbnail";
- private static final String COLUMN_PREVIEW = "preview";
- private static final String MIME_TYPE_PNG = "image/png";
- private static final String CONTENT_SCHEME = "content";
- private static final String AUTHORITY = "com.android.keyguard.clock";
-
- @Inject
- public Provider<List<ClockInfo>> mClockInfosProvider;
-
- @VisibleForTesting
- ClockOptionsProvider(Provider<List<ClockInfo>> clockInfosProvider) {
- mClockInfosProvider = clockInfosProvider;
- }
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public String getType(Uri uri) {
- List<String> segments = uri.getPathSegments();
- if (segments.size() > 0 && (KEY_PREVIEW.equals(segments.get(0))
- || KEY_THUMBNAIL.equals(segments.get(0)))) {
- return MIME_TYPE_PNG;
- }
- return "vnd.android.cursor.dir/clock_faces";
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- if (!KEY_LIST_OPTIONS.equals(uri.getPath())) {
- return null;
- }
- MatrixCursor cursor = new MatrixCursor(new String[] {
- COLUMN_NAME, COLUMN_TITLE, COLUMN_ID, COLUMN_THUMBNAIL, COLUMN_PREVIEW});
- List<ClockInfo> clocks = mClockInfosProvider.get();
- for (int i = 0; i < clocks.size(); i++) {
- ClockInfo clock = clocks.get(i);
- cursor.newRow()
- .add(COLUMN_NAME, clock.getName())
- .add(COLUMN_TITLE, clock.getTitle())
- .add(COLUMN_ID, clock.getId())
- .add(COLUMN_THUMBNAIL, createThumbnailUri(clock))
- .add(COLUMN_PREVIEW, createPreviewUri(clock));
- }
- return cursor;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- List<String> segments = uri.getPathSegments();
- if (segments.size() != 2 || !(KEY_PREVIEW.equals(segments.get(0))
- || KEY_THUMBNAIL.equals(segments.get(0)))) {
- throw new FileNotFoundException("Invalid preview url");
- }
- String id = segments.get(1);
- if (TextUtils.isEmpty(id)) {
- throw new FileNotFoundException("Invalid preview url, missing id");
- }
- ClockInfo clock = null;
- List<ClockInfo> clocks = mClockInfosProvider.get();
- for (int i = 0; i < clocks.size(); i++) {
- if (id.equals(clocks.get(i).getId())) {
- clock = clocks.get(i);
- break;
- }
- }
- if (clock == null) {
- throw new FileNotFoundException("Invalid preview url, id not found");
- }
- return openPipeHelper(uri, MIME_TYPE_PNG, null, KEY_PREVIEW.equals(segments.get(0))
- ? clock.getPreview() : clock.getThumbnail(), new MyWriter());
- }
-
- private Uri createThumbnailUri(ClockInfo clock) {
- return new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(KEY_THUMBNAIL)
- .appendPath(clock.getId())
- .build();
- }
-
- private Uri createPreviewUri(ClockInfo clock) {
- return new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(KEY_PREVIEW)
- .appendPath(clock.getId())
- .build();
- }
-
- private static class MyWriter implements ContentProvider.PipeDataWriter<Bitmap> {
- @Override
- public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
- Bundle opts, Bitmap bitmap) {
- try (AutoCloseOutputStream os = new AutoCloseOutputStream(output)) {
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
- } catch (Exception e) {
- Log.w(TAG, "fail to write to pipe", e);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt b/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
deleted file mode 100644
index 5c5493a..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
+++ /dev/null
@@ -1,73 +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.keyguard.clock
-
-import android.graphics.Color
-import android.util.MathUtils
-
-private const val PRIMARY_INDEX = 5
-private const val SECONDARY_DARK_INDEX = 8
-private const val SECONDARY_LIGHT_INDEX = 2
-
-/**
- * A helper class to extract colors from a clock face.
- */
-class ClockPalette {
-
- private var darkAmount: Float = 0f
- private var accentPrimary: Int = Color.WHITE
- private var accentSecondaryLight: Int = Color.WHITE
- private var accentSecondaryDark: Int = Color.BLACK
- private val lightHSV: FloatArray = FloatArray(3)
- private val darkHSV: FloatArray = FloatArray(3)
- private val hsv: FloatArray = FloatArray(3)
-
- /** Returns a color from the palette as an RGB packed int. */
- fun getPrimaryColor(): Int {
- return accentPrimary
- }
-
- /** Returns either a light or dark color from the palette as an RGB packed int. */
- fun getSecondaryColor(): Int {
- Color.colorToHSV(accentSecondaryLight, lightHSV)
- Color.colorToHSV(accentSecondaryDark, darkHSV)
- for (i in 0..2) {
- hsv[i] = MathUtils.lerp(darkHSV[i], lightHSV[i], darkAmount)
- }
- return Color.HSVToColor(hsv)
- }
-
- /** See {@link ClockPlugin#setColorPalette}. */
- fun setColorPalette(supportsDarkText: Boolean, colorPalette: IntArray?) {
- if (colorPalette == null || colorPalette.isEmpty()) {
- accentPrimary = Color.WHITE
- accentSecondaryLight = Color.WHITE
- accentSecondaryDark = if (supportsDarkText) Color.BLACK else Color.WHITE
- return
- }
- val length = colorPalette.size
- accentPrimary = colorPalette[Math.max(0, length - PRIMARY_INDEX)]
- accentSecondaryLight = colorPalette[Math.max(0, length - SECONDARY_LIGHT_INDEX)]
- accentSecondaryDark = colorPalette[Math.max(0,
- length - if (supportsDarkText) SECONDARY_DARK_INDEX else SECONDARY_LIGHT_INDEX)]
- }
-
- /** See {@link ClockPlugin#setDarkAmount}. */
- fun setDarkAmount(darkAmount: Float) {
- this.darkAmount = darkAmount
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
deleted file mode 100644
index 3c3f475..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
+++ /dev/null
@@ -1,62 +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.keyguard.clock;
-
-import android.view.View;
-
-/**
- * Controls transition to dark state by cross fading between views.
- */
-final class CrossFadeDarkController {
-
- private final View mFadeInView;
- private final View mFadeOutView;
-
- /**
- * Creates a new controller that fades between views.
- *
- * @param fadeInView View to fade in when transitioning to AOD.
- * @param fadeOutView View to fade out when transitioning to AOD.
- */
- CrossFadeDarkController(View fadeInView, View fadeOutView) {
- mFadeInView = fadeInView;
- mFadeOutView = fadeOutView;
- }
-
- /**
- * Sets the amount the system has transitioned to the dark state.
- *
- * @param darkAmount Amount of transition to dark state: 1f for AOD and 0f for lock screen.
- */
- void setDarkAmount(float darkAmount) {
- mFadeInView.setAlpha(Math.max(0f, 2f * darkAmount - 1f));
- if (darkAmount == 0f) {
- mFadeInView.setVisibility(View.GONE);
- } else {
- if (mFadeInView.getVisibility() == View.GONE) {
- mFadeInView.setVisibility(View.VISIBLE);
- }
- }
- mFadeOutView.setAlpha(Math.max(0f, 1f - 2f * darkAmount));
- if (darkAmount == 1f) {
- mFadeOutView.setVisibility(View.GONE);
- } else {
- if (mFadeOutView.getVisibility() == View.GONE) {
- mFadeOutView.setVisibility(View.VISIBLE);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
deleted file mode 100644
index c81935a..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
+++ /dev/null
@@ -1,178 +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.keyguard.clock;
-
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Paint.Style;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.ClockPlugin;
-
-import java.util.TimeZone;
-
-/**
- * Plugin for the default clock face used only to provide a preview.
- */
-public class DefaultClockController implements ClockPlugin {
-
- /**
- * Resources used to get title and thumbnail.
- */
- private final Resources mResources;
-
- /**
- * LayoutInflater used to inflate custom clock views.
- */
- private final LayoutInflater mLayoutInflater;
-
- /**
- * Extracts accent color from wallpaper.
- */
- private final SysuiColorExtractor mColorExtractor;
-
- /**
- * Renders preview from clock view.
- */
- private final ViewPreviewer mRenderer = new ViewPreviewer();
-
- /**
- * Root view of preview.
- */
- private View mView;
-
- /**
- * Text clock in preview view hierarchy.
- */
- private TextView mTextTime;
-
- /**
- * Date showing below time in preview view hierarchy.
- */
- private TextView mTextDate;
-
- /**
- * Create a DefaultClockController instance.
- *
- * @param res Resources contains title and thumbnail.
- * @param inflater Inflater used to inflate custom clock views.
- * @param colorExtractor Extracts accent color from wallpaper.
- */
- public DefaultClockController(Resources res, LayoutInflater inflater,
- SysuiColorExtractor colorExtractor) {
- mResources = res;
- mLayoutInflater = inflater;
- mColorExtractor = colorExtractor;
- }
-
- private void createViews() {
- mView = mLayoutInflater.inflate(R.layout.default_clock_preview, null);
- mTextTime = mView.findViewById(R.id.time);
- mTextDate = mView.findViewById(R.id.date);
- }
-
- @Override
- public void onDestroyView() {
- mView = null;
- mTextTime = null;
- mTextDate = null;
- }
-
- @Override
- public String getName() {
- return "default";
- }
-
- @Override
- public String getTitle() {
- return mResources.getString(R.string.clock_title_default);
- }
-
- @Override
- public Bitmap getThumbnail() {
- return BitmapFactory.decodeResource(mResources, R.drawable.default_thumbnail);
- }
-
- @Override
- public Bitmap getPreview(int width, int height) {
-
- // Use the big clock view for the preview
- View view = getBigClockView();
-
- // Initialize state of plugin before generating preview.
- setDarkAmount(1f);
- setTextColor(Color.WHITE);
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK);
- setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
- onTimeTick();
-
- return mRenderer.createPreview(view, width, height);
- }
-
- @Override
- public View getView() {
- return null;
- }
-
- @Override
- public View getBigClockView() {
- if (mView == null) {
- createViews();
- }
- return mView;
- }
-
- @Override
- public int getPreferredY(int totalHeight) {
- return totalHeight / 2;
- }
-
- @Override
- public void setStyle(Style style) {}
-
- @Override
- public void setTextColor(int color) {
- mTextTime.setTextColor(color);
- mTextDate.setTextColor(color);
- }
-
- @Override
- public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {}
-
- @Override
- public void onTimeTick() {
- }
-
- @Override
- public void setDarkAmount(float darkAmount) {}
-
- @Override
- public void onTimeZoneChanged(TimeZone timeZone) {}
-
- @Override
- public boolean shouldShowStatusArea() {
- return true;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
deleted file mode 100644
index 34c041b..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
+++ /dev/null
@@ -1,103 +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.keyguard.clock;
-
-import android.content.Context;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * Clock composed of two images that rotate with the time.
- *
- * The images are the clock hands. ImageClock expects two child ImageViews
- * with ids hour_hand and minute_hand.
- */
-public class ImageClock extends FrameLayout {
-
- private ImageView mHourHand;
- private ImageView mMinuteHand;
- private final Calendar mTime = Calendar.getInstance(TimeZone.getDefault());
- private String mDescFormat;
- private TimeZone mTimeZone;
-
- public ImageClock(Context context) {
- this(context, null);
- }
-
- public ImageClock(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ImageClock(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
- }
-
- /**
- * Call when the time changes to update the rotation of the clock hands.
- */
- public void onTimeChanged() {
- mTime.setTimeInMillis(System.currentTimeMillis());
- final float hourAngle = mTime.get(Calendar.HOUR) * 30f + mTime.get(Calendar.MINUTE) * 0.5f;
- mHourHand.setRotation(hourAngle);
- final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
- mMinuteHand.setRotation(minuteAngle);
- setContentDescription(DateFormat.format(mDescFormat, mTime));
- invalidate();
- }
-
- /**
- * Call when the time zone has changed to update clock hands.
- *
- * @param timeZone The updated time zone that will be used.
- */
- public void onTimeZoneChanged(TimeZone timeZone) {
- mTimeZone = timeZone;
- mTime.setTimeZone(timeZone);
- }
-
- /**
- * Sets the colors to use on the clock face.
- * @param dark Darker color obtained from color palette.
- * @param light Lighter color obtained from color palette.
- */
- public void setClockColors(int dark, int light) {
- mHourHand.setColorFilter(dark);
- mMinuteHand.setColorFilter(light);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mHourHand = findViewById(R.id.hour_hand);
- mMinuteHand = findViewById(R.id.minute_hand);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mTime.setTimeZone(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
- onTimeChanged();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
deleted file mode 100644
index 096e943..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
+++ /dev/null
@@ -1,137 +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.keyguard.clock;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Wrapper around Settings used for testing.
- */
-public class SettingsWrapper {
-
- private static final String TAG = "ClockFaceSettings";
- private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE;
- private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE;
- private static final String CLOCK_FIELD = "clock";
-
- private final ContentResolver mContentResolver;
- private final Migration mMigration;
-
- SettingsWrapper(ContentResolver contentResolver) {
- this(contentResolver, new Migrator(contentResolver));
- }
-
- @VisibleForTesting
- SettingsWrapper(ContentResolver contentResolver, Migration migration) {
- mContentResolver = contentResolver;
- mMigration = migration;
- }
-
- /**
- * Gets the value stored in settings for the custom clock face.
- *
- * @param userId ID of the user.
- */
- String getLockScreenCustomClockFace(int userId) {
- return decode(
- Settings.Secure.getStringForUser(mContentResolver, CUSTOM_CLOCK_FACE, userId),
- userId);
- }
-
- /**
- * Gets the value stored in settings for the clock face to use when docked.
- *
- * @param userId ID of the user.
- */
- String getDockedClockFace(int userId) {
- return Settings.Secure.getStringForUser(mContentResolver, DOCKED_CLOCK_FACE, userId);
- }
-
- /**
- * Decodes the string stored in settings, which should be formatted as JSON.
- * @param value String stored in settings. If value is not JSON, then the settings is
- * overwritten with JSON containing the prior value.
- * @return ID of the clock face to show on AOD and lock screen. If value is not JSON, the value
- * is returned.
- */
- @VisibleForTesting
- String decode(@Nullable String value, int userId) {
- if (value == null) {
- return value;
- }
- JSONObject json;
- try {
- json = new JSONObject(value);
- } catch (JSONException ex) {
- Log.e(TAG, "Settings value is not valid JSON", ex);
- // The settings value isn't JSON since it didn't parse so migrate the value to JSON.
- // TODO(b/135674383): Remove this migration path in the following release.
- mMigration.migrate(value, userId);
- return value;
- }
- try {
- return json.getString(CLOCK_FIELD);
- } catch (JSONException ex) {
- Log.e(TAG, "JSON object does not contain clock field.", ex);
- return null;
- }
- }
-
- interface Migration {
- void migrate(String value, int userId);
- }
-
- /**
- * Implementation of {@link Migration} that writes valid JSON back to Settings.
- */
- private static final class Migrator implements Migration {
-
- private final ContentResolver mContentResolver;
-
- Migrator(ContentResolver contentResolver) {
- mContentResolver = contentResolver;
- }
-
- /**
- * Migrate settings values that don't parse by converting to JSON format.
- *
- * Values in settings must be JSON to be backed up and restored. To help users maintain
- * their current settings, convert existing values into the JSON format.
- *
- * TODO(b/135674383): Remove this migration code in the following release.
- */
- @Override
- public void migrate(String value, int userId) {
- try {
- JSONObject json = new JSONObject();
- json.put(CLOCK_FIELD, value);
- Settings.Secure.putStringForUser(mContentResolver, CUSTOM_CLOCK_FACE,
- json.toString(),
- userId);
- } catch (JSONException ex) {
- Log.e(TAG, "Failed migrating settings value to JSON format", ex);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java b/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java
deleted file mode 100644
index 4e51b98..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java
+++ /dev/null
@@ -1,78 +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.keyguard.clock;
-
-import android.content.Context;
-import android.util.MathUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.R;
-
-/**
- * Computes preferred position of clock by considering height of status bar and lock icon.
- */
-class SmallClockPosition {
-
- /**
- * Dimensions used to determine preferred clock position.
- */
- private final int mStatusBarHeight;
- private final int mKeyguardLockPadding;
- private final int mKeyguardLockHeight;
- private final int mBurnInOffsetY;
-
- /**
- * Amount of transition between AOD and lock screen.
- */
- private float mDarkAmount;
-
- SmallClockPosition(Context context) {
- this(SystemBarUtils.getStatusBarHeight(context),
- context.getResources().getDimensionPixelSize(R.dimen.keyguard_lock_padding),
- context.getResources().getDimensionPixelSize(R.dimen.keyguard_lock_height),
- context.getResources().getDimensionPixelSize(R.dimen.burn_in_prevention_offset_y)
- );
- }
-
- @VisibleForTesting
- SmallClockPosition(int statusBarHeight, int lockPadding, int lockHeight, int burnInY) {
- mStatusBarHeight = statusBarHeight;
- mKeyguardLockPadding = lockPadding;
- mKeyguardLockHeight = lockHeight;
- mBurnInOffsetY = burnInY;
- }
-
- /**
- * See {@link ClockPlugin#setDarkAmount}.
- */
- void setDarkAmount(float darkAmount) {
- mDarkAmount = darkAmount;
- }
-
- /**
- * Gets the preferred Y position accounting for status bar and lock icon heights.
- */
- int getPreferredY() {
- // On AOD, clock needs to appear below the status bar with enough room for pixel shifting
- int aodY = mStatusBarHeight + mKeyguardLockHeight + 2 * mKeyguardLockPadding
- + mBurnInOffsetY;
- // On lock screen, clock needs to appear below the lock icon
- int lockY = mStatusBarHeight + mKeyguardLockHeight + 2 * mKeyguardLockPadding;
- return (int) MathUtils.lerp(lockY, aodY, mDarkAmount);
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java b/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java
deleted file mode 100644
index abd0dd2..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java
+++ /dev/null
@@ -1,105 +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.keyguard.clock;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
-
-/**
- * Creates a preview image ({@link Bitmap}) of a {@link View} for a custom clock face.
- */
-final class ViewPreviewer {
-
- private static final String TAG = "ViewPreviewer";
-
- /**
- * Handler used to run {@link View#draw(Canvas)} on the main thread.
- */
- private final Handler mMainHandler = new Handler(Looper.getMainLooper());
-
- /**
- * Generate a realistic preview of a clock face.
- *
- * @param view view is used to generate preview image.
- * @param width width of the preview image, should be the same as device width in pixels.
- * @param height height of the preview image, should be the same as device height in pixels.
- * @return bitmap of view.
- */
- @Nullable
- Bitmap createPreview(View view, int width, int height) {
- if (view == null) {
- return null;
- }
- FutureTask<Bitmap> task = new FutureTask<>(new Callable<Bitmap>() {
- @Override
- public Bitmap call() {
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-
- // Draw clock view hierarchy to canvas.
- Canvas canvas = new Canvas(bitmap);
- canvas.drawColor(Color.BLACK);
- dispatchVisibilityAggregated(view, true);
- view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
- view.layout(0, 0, width, height);
- view.draw(canvas);
-
- return bitmap;
- }
- });
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- task.run();
- } else {
- mMainHandler.post(task);
- }
-
- try {
- return task.get();
- } catch (Exception e) {
- Log.e(TAG, "Error completing task", e);
- return null;
- }
- }
-
- private void dispatchVisibilityAggregated(View view, boolean isVisible) {
- // Similar to View.dispatchVisibilityAggregated implementation.
- final boolean thisVisible = view.getVisibility() == View.VISIBLE;
- if (thisVisible || !isVisible) {
- view.onVisibilityAggregated(isVisible);
- }
-
- if (view instanceof ViewGroup) {
- isVisible = thisVisible && isVisible;
- ViewGroup vg = (ViewGroup) view;
- int count = vg.getChildCount();
-
- for (int i = 0; i < count; i++) {
- dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index d2b10d6..83fc278 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -71,7 +71,8 @@
context.getString(R.string.lockscreen_clock_id_fallback),
logBuffer,
/* keepAllLoaded = */ false,
- /* subTag = */ "System");
+ /* subTag = */ "System",
+ /* isTransitClockEnabled = */ featureFlags.isEnabled(Flags.TRANSIT_CLOCK));
registry.registerListeners();
return registry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index be5bb07..1f1b154 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -33,7 +33,6 @@
import com.android.internal.util.Preconditions;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.clock.ClockManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
@@ -323,7 +322,6 @@
@Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
@Inject @Main Lazy<Executor> mMainExecutor;
@Inject @Background Lazy<Executor> mBackgroundExecutor;
- @Inject Lazy<ClockManager> mClockManager;
@Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
@Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
@Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
@@ -517,7 +515,6 @@
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
mRemoteInputQuickSettingsDisabler::get);
- mProviders.put(ClockManager.class, mClockManager::get);
mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 99dd6b6..670c1fa 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -49,8 +49,11 @@
* When the HWC of the device supports Composition.DISPLAY_DECORATION, we use this layer to draw
* screen decorations.
*/
-class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDecorationSupport) :
- DisplayCutoutBaseView(context) {
+class ScreenDecorHwcLayer(
+ context: Context,
+ displayDecorationSupport: DisplayDecorationSupport,
+ private val debug: Boolean,
+) : DisplayCutoutBaseView(context) {
val colorMode: Int
private val useInvertedAlphaColor: Boolean
private val color: Int
@@ -74,7 +77,7 @@
throw IllegalArgumentException("Attempting to use unsupported mode " +
"${PixelFormat.formatToString(displayDecorationSupport.format)}")
}
- if (DEBUG_COLOR) {
+ if (debug) {
color = Color.GREEN
bgColor = Color.TRANSPARENT
colorMode = ActivityInfo.COLOR_MODE_DEFAULT
@@ -106,7 +109,7 @@
override fun onAttachedToWindow() {
super.onAttachedToWindow()
parent.requestTransparentRegion(this)
- if (!DEBUG_COLOR) {
+ if (!debug) {
viewRootImpl.setDisplayDecoration(true)
}
@@ -143,12 +146,12 @@
override fun gatherTransparentRegion(region: Region?): Boolean {
region?.let {
calculateTransparentRect()
- if (DEBUG_COLOR) {
+ if (debug) {
// Since we're going to draw a rectangle where the layer would
// normally be transparent, treat the transparent region as
// empty. We still want this method to be called, though, so
// that it calculates the transparent rect at the right time
- // to match !DEBUG_COLOR.
+ // to match ![debug]
region.setEmpty()
} else {
region.op(transparentRect, Region.Op.INTERSECT)
@@ -421,8 +424,4 @@
ipw.println("roundedCornerBottomSize=$roundedCornerBottomSize")
ipw.decreaseIndent()
}
-
- companion object {
- private val DEBUG_COLOR = ScreenDecorations.DEBUG_COLOR
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index ea0f343..67d4a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -71,6 +71,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.decor.CutoutDecorProviderFactory;
+import com.android.systemui.decor.DebugRoundedCornerDelegate;
import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.DecorProviderKt;
@@ -78,14 +79,12 @@
import com.android.systemui.decor.OverlayWindow;
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
import com.android.systemui.decor.RoundedCornerDecorProviderFactory;
-import com.android.systemui.decor.RoundedCornerResDelegate;
+import com.android.systemui.decor.RoundedCornerResDelegateImpl;
import com.android.systemui.log.ScreenDecorationsLogger;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.ThreadFactory;
import com.android.systemui.util.settings.SecureSettings;
@@ -105,19 +104,17 @@
* for antialiasing and emulation purposes.
*/
@SysUISingleton
-public class ScreenDecorations implements CoreStartable, Tunable , Dumpable {
- private static final boolean DEBUG = false;
+public class ScreenDecorations implements CoreStartable, Dumpable {
+ private static final boolean DEBUG_LOGGING = false;
private static final String TAG = "ScreenDecorations";
- public static final String SIZE = "sysui_rounded_size";
- public static final String PADDING = "sysui_rounded_content_padding";
// Provide a way for factory to disable ScreenDecorations to run the Display tests.
private static final boolean DEBUG_DISABLE_SCREEN_DECORATIONS =
SystemProperties.getBoolean("debug.disable_screen_decorations", false);
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
- private static final boolean VERBOSE = false;
- static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
+ private boolean mDebug = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
+ private int mDebugColor = Color.RED;
private static final int[] DISPLAY_CUTOUT_IDS = {
R.id.display_cutout,
@@ -134,7 +131,6 @@
protected boolean mIsRegistered;
private final Context mContext;
private final Executor mMainExecutor;
- private final TunerService mTunerService;
private final SecureSettings mSecureSettings;
@VisibleForTesting
DisplayTracker.Callback mDisplayListener;
@@ -147,9 +143,13 @@
public final int mFaceScanningViewId;
@VisibleForTesting
- protected RoundedCornerResDelegate mRoundedCornerResDelegate;
+ protected RoundedCornerResDelegateImpl mRoundedCornerResDelegate;
@VisibleForTesting
protected DecorProviderFactory mRoundedCornerFactory;
+ @VisibleForTesting
+ protected DebugRoundedCornerDelegate mDebugRoundedCornerDelegate =
+ new DebugRoundedCornerDelegate();
+ protected DecorProviderFactory mDebugRoundedCornerFactory;
private CutoutDecorProviderFactory mCutoutFactory;
private int mProviderRefreshToken = 0;
@VisibleForTesting
@@ -315,7 +315,6 @@
public ScreenDecorations(Context context,
@Main Executor mainExecutor,
SecureSettings secureSettings,
- TunerService tunerService,
UserTracker userTracker,
DisplayTracker displayTracker,
PrivacyDotViewController dotViewController,
@@ -327,7 +326,6 @@
mContext = context;
mMainExecutor = mainExecutor;
mSecureSettings = secureSettings;
- mTunerService = tunerService;
mUserTracker = userTracker;
mDisplayTracker = displayTracker;
mDotViewController = dotViewController;
@@ -365,16 +363,47 @@
mAuthController.addCallback(mAuthControllerCallback);
}
+ /**
+ * Change the value of {@link ScreenDecorations#mDebug}. This operation is heavyweight, since
+ * it requires essentially re-init-ing this screen decorations process with the debug
+ * information taken into account.
+ */
+ @VisibleForTesting
+ protected void setDebug(boolean debug) {
+ if (mDebug == debug) {
+ return;
+ }
+
+ mDebug = debug;
+ if (!mDebug) {
+ mDebugRoundedCornerDelegate.removeDebugState();
+ }
+
+ mExecutor.execute(() -> {
+ // Re-trigger all of the screen decorations setup here so that the debug values
+ // can be picked up
+ removeAllOverlays();
+ removeHwcOverlay();
+ startOnScreenDecorationsThread();
+ updateColorInversionDefault();
+ });
+ }
+
private boolean isPrivacyDotEnabled() {
return mDotFactory.getHasProviders();
}
@NonNull
- private List<DecorProvider> getProviders(boolean hasHwLayer) {
+ @VisibleForTesting
+ protected List<DecorProvider> getProviders(boolean hasHwLayer) {
List<DecorProvider> decorProviders = new ArrayList<>(mDotFactory.getProviders());
decorProviders.addAll(mFaceScanningFactory.getProviders());
if (!hasHwLayer) {
- decorProviders.addAll(mRoundedCornerFactory.getProviders());
+ if (mDebug && mDebugRoundedCornerFactory.getHasProviders()) {
+ decorProviders.addAll(mDebugRoundedCornerFactory.getProviders());
+ } else {
+ decorProviders.addAll(mRoundedCornerFactory.getProviders());
+ }
decorProviders.addAll(mCutoutFactory.getProviders());
}
return decorProviders;
@@ -416,11 +445,13 @@
mDisplayMode = mDisplayInfo.getMode();
mDisplayUniqueId = mDisplayInfo.uniqueId;
mDisplayCutout = mDisplayInfo.displayCutout;
- mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
- mDisplayUniqueId);
+ mRoundedCornerResDelegate =
+ new RoundedCornerResDelegateImpl(mContext.getResources(), mDisplayUniqueId);
mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
getPhysicalPixelDisplaySizeRatio());
mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
+ mDebugRoundedCornerFactory =
+ new RoundedCornerDecorProviderFactory(mDebugRoundedCornerDelegate);
mCutoutFactory = getCutoutFactory();
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
updateHwLayerRoundedCornerDrawable();
@@ -444,15 +475,12 @@
// - we are trying to redraw. This because WM resized our window and told us to.
// - the config change has been dispatched, so WM is no longer deferring layout.
mPendingConfigChange = true;
- if (DEBUG) {
- if (mRotation != newRotation) {
- Log.i(TAG, "Rotation changed, deferring " + newRotation
- + ", staying at " + mRotation);
- }
- if (displayModeChanged(mDisplayMode, newDisplayMode)) {
- Log.i(TAG, "Resolution changed, deferring " + newDisplayMode
- + ", staying at " + mDisplayMode);
- }
+ if (mRotation != newRotation) {
+ mLogger.logRotationChangeDeferred(mRotation, newRotation);
+ }
+ if (displayModeChanged(mDisplayMode, newDisplayMode)) {
+ mLogger.logDisplayModeChanged(
+ newDisplayMode.getModeId(), mDisplayMode.getModeId());
}
if (mOverlays != null) {
@@ -608,12 +636,6 @@
return;
}
- mMainExecutor.execute(() -> {
- Trace.beginSection("ScreenDecorations#addTunable");
- mTunerService.addTunable(this, SIZE);
- Trace.endSection();
- });
-
// Watch color inversion and invert the overlay as needed.
if (mColorInversionSetting == null) {
mColorInversionSetting = new SettingObserver(mSecureSettings, mHandler,
@@ -632,12 +654,6 @@
mUserTracker.addCallback(mUserChangedCallback, mExecutor);
mIsRegistered = true;
} else {
- mMainExecutor.execute(() -> {
- Trace.beginSection("ScreenDecorations#removeTunable");
- mTunerService.removeTunable(this);
- Trace.endSection();
- });
-
if (mColorInversionSetting != null) {
mColorInversionSetting.setListening(false);
}
@@ -777,7 +793,8 @@
}
mScreenDecorHwcWindow = (ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.screen_decor_hwc_layer, null);
- mScreenDecorHwcLayer = new ScreenDecorHwcLayer(mContext, mHwcScreenDecorationSupport);
+ mScreenDecorHwcLayer =
+ new ScreenDecorHwcLayer(mContext, mHwcScreenDecorationSupport, mDebug);
mScreenDecorHwcWindow.addView(mScreenDecorHwcLayer, new FrameLayout.LayoutParams(
MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.START));
mWindowManager.addView(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
@@ -825,7 +842,7 @@
lp.height = MATCH_PARENT;
lp.setTitle("ScreenDecorHwcOverlay");
lp.gravity = Gravity.TOP | Gravity.START;
- if (!DEBUG_COLOR) {
+ if (!mDebug) {
lp.setColorMode(ActivityInfo.COLOR_MODE_A8);
}
return lp;
@@ -933,19 +950,42 @@
new UserTracker.Callback() {
@Override
public void onUserChanged(int newUser, @NonNull Context userContext) {
- if (DEBUG) {
- Log.d(TAG, "UserSwitched newUserId=" + newUser);
- }
+ mLogger.logUserSwitched(newUser);
// update color inversion setting to the new user
mColorInversionSetting.setUserId(newUser);
updateColorInversion(mColorInversionSetting.getValue());
}
};
+ /**
+ * Use the current value of {@link ScreenDecorations#mColorInversionSetting} and passes it
+ * to {@link ScreenDecorations#updateColorInversion}
+ */
+ private void updateColorInversionDefault() {
+ int inversion = 0;
+ if (mColorInversionSetting != null) {
+ inversion = mColorInversionSetting.getValue();
+ }
+
+ updateColorInversion(inversion);
+ }
+
+ /**
+ * Update the tint color of screen decoration assets. Defaults to Color.BLACK. In the case of
+ * a color inversion being set, use Color.WHITE (which inverts to black).
+ *
+ * When {@link ScreenDecorations#mDebug} is {@code true}, this value is updated to use
+ * {@link ScreenDecorations#mDebugColor}, and does not handle inversion.
+ *
+ * @param colorsInvertedValue if non-zero, assume that colors are inverted, and use Color.WHITE
+ * for screen decoration tint
+ */
private void updateColorInversion(int colorsInvertedValue) {
mTintColor = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
- if (DEBUG_COLOR) {
- mTintColor = Color.RED;
+ if (mDebug) {
+ mTintColor = mDebugColor;
+ mDebugRoundedCornerDelegate.setColor(mTintColor);
+ //TODO(b/285941724): update the hwc layer color here too (or disable it in debug mode)
}
updateOverlayProviderViews(new Integer[] {
@@ -986,7 +1026,9 @@
int oldRotation = mRotation;
mPendingConfigChange = false;
updateConfiguration();
- if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
+ if (oldRotation != mRotation) {
+ mLogger.logRotationChanged(oldRotation, mRotation);
+ }
setupDecorations();
if (mOverlays != null) {
// Updating the layout params ensures that ViewRootImpl will call relayoutWindow(),
@@ -1016,6 +1058,7 @@
if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
return;
}
+ ipw.println("mDebug:" + mDebug);
ipw.println("mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
ipw.println("shouldOptimizeOverlayVisibility:" + shouldOptimizeVisibility());
@@ -1071,6 +1114,7 @@
}
}
mRoundedCornerResDelegate.dump(pw, args);
+ mDebugRoundedCornerDelegate.dump(pw);
}
@VisibleForTesting
@@ -1093,8 +1137,9 @@
mRotation = newRotation;
mDisplayMode = newMod;
mDisplayCutout = newCutout;
- mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
- getPhysicalPixelDisplaySizeRatio());
+ float ratio = getPhysicalPixelDisplaySizeRatio();
+ mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(ratio);
+ mDebugRoundedCornerDelegate.setPhysicalPixelDisplaySizeRatio(ratio);
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.pendingConfigChange = false;
mScreenDecorHwcLayer.updateConfiguration(mDisplayUniqueId);
@@ -1117,7 +1162,8 @@
}
private boolean hasRoundedCorners() {
- return mRoundedCornerFactory.getHasProviders();
+ return mRoundedCornerFactory.getHasProviders()
+ || mDebugRoundedCornerFactory.getHasProviders();
}
private boolean shouldOptimizeVisibility() {
@@ -1170,41 +1216,17 @@
Trace.endSection();
}
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
- Log.i(TAG, "ScreenDecorations is disabled");
- return;
- }
- mExecutor.execute(() -> {
- if (mOverlays == null || !SIZE.equals(key)) {
- return;
- }
- Trace.beginSection("ScreenDecorations#onTuningChanged");
- try {
- final int sizeFactor = Integer.parseInt(newValue);
- mRoundedCornerResDelegate.setTuningSizeFactor(sizeFactor);
- } catch (NumberFormatException e) {
- mRoundedCornerResDelegate.setTuningSizeFactor(null);
- }
- updateOverlayProviderViews(new Integer[] {
- R.id.rounded_corner_top_left,
- R.id.rounded_corner_top_right,
- R.id.rounded_corner_bottom_left,
- R.id.rounded_corner_bottom_right
- });
- updateHwLayerRoundedCornerExistAndSize();
- Trace.endSection();
- });
- }
-
private void updateHwLayerRoundedCornerDrawable() {
if (mScreenDecorHwcLayer == null) {
return;
}
- final Drawable topDrawable = mRoundedCornerResDelegate.getTopRoundedDrawable();
- final Drawable bottomDrawable = mRoundedCornerResDelegate.getBottomRoundedDrawable();
+ Drawable topDrawable = mRoundedCornerResDelegate.getTopRoundedDrawable();
+ Drawable bottomDrawable = mRoundedCornerResDelegate.getBottomRoundedDrawable();
+ if (mDebug && (mDebugRoundedCornerFactory.getHasProviders())) {
+ topDrawable = mDebugRoundedCornerDelegate.getTopRoundedDrawable();
+ bottomDrawable = mDebugRoundedCornerDelegate.getBottomRoundedDrawable();
+ }
if (topDrawable == null || bottomDrawable == null) {
return;
@@ -1216,11 +1238,19 @@
if (mScreenDecorHwcLayer == null) {
return;
}
- mScreenDecorHwcLayer.updateRoundedCornerExistenceAndSize(
- mRoundedCornerResDelegate.getHasTop(),
- mRoundedCornerResDelegate.getHasBottom(),
- mRoundedCornerResDelegate.getTopRoundedSize().getWidth(),
- mRoundedCornerResDelegate.getBottomRoundedSize().getWidth());
+ if (mDebug && mDebugRoundedCornerFactory.getHasProviders()) {
+ mScreenDecorHwcLayer.updateRoundedCornerExistenceAndSize(
+ mDebugRoundedCornerDelegate.getHasTop(),
+ mDebugRoundedCornerDelegate.getHasBottom(),
+ mDebugRoundedCornerDelegate.getTopRoundedSize().getWidth(),
+ mDebugRoundedCornerDelegate.getBottomRoundedSize().getWidth());
+ } else {
+ mScreenDecorHwcLayer.updateRoundedCornerExistenceAndSize(
+ mRoundedCornerResDelegate.getHasTop(),
+ mRoundedCornerResDelegate.getHasBottom(),
+ mRoundedCornerResDelegate.getTopRoundedSize().getWidth(),
+ mRoundedCornerResDelegate.getBottomRoundedSize().getWidth());
+ }
}
@VisibleForTesting
@@ -1247,7 +1277,7 @@
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
- if (DEBUG) {
+ if (DEBUG_LOGGING) {
getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
getWindowTitleByPos(pos) + " drawn in rot " + mRotation));
}
@@ -1440,7 +1470,7 @@
mView.getViewTreeObserver().removeOnPreDrawListener(this);
if (mTargetRotation == mRotation
&& !displayModeChanged(mDisplayMode, mTargetDisplayMode)) {
- if (DEBUG) {
+ if (DEBUG_LOGGING) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition);
Log.i(TAG, title + " already in target rot "
@@ -1456,7 +1486,7 @@
// This changes the window attributes - we need to restart the traversal for them to
// take effect.
updateConfiguration();
- if (DEBUG) {
+ if (DEBUG_LOGGING) {
final String title = mPosition < 0 ? "ScreenDecorHwcLayer"
: getWindowTitleByPos(mPosition);
Log.i(TAG, title
@@ -1491,7 +1521,7 @@
final Display.Mode displayMode = mDisplayInfo.getMode();
if ((displayRotation != mRotation || displayModeChanged(mDisplayMode, displayMode))
&& !mPendingConfigChange) {
- if (DEBUG) {
+ if (DEBUG_LOGGING) {
if (displayRotation != mRotation) {
Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+ displayRotation + ". Restarting draw");
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityLogger.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityLogger.kt
index 7b91596..9e3a778 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityLogger.kt
@@ -16,8 +16,11 @@
package com.android.systemui.accessibility
+import com.android.internal.annotations.GuardedBy
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
/**
@@ -25,16 +28,60 @@
*
* See go/uievent
*/
-class AccessibilityLogger @Inject constructor(private val uiEventLogger: UiEventLogger) {
+class AccessibilityLogger
+@Inject
+constructor(private val uiEventLogger: UiEventLogger, private val clock: SystemClock) {
+
+ @GuardedBy("clock") private var lastTimeThrottledMs: Long = 0
+ @GuardedBy("clock") private var lastEventThrottled: UiEventEnum? = null
+
+ /**
+ * Logs the event, but any additional calls within the given delay window are ignored. The
+ * window resets every time a new event is received. i.e. it will only log one time until you
+ * wait at least [delayBeforeLoggingMs] before sending the next event.
+ *
+ * <p>Additionally, if a different type of event is passed in, the delay window for the previous
+ * one is forgotten. e.g. if you send two types of events interlaced all within the delay
+ * window, e.g. A->B->A within 1000ms, all three will be logged.
+ */
+ @JvmOverloads fun logThrottled(event: UiEventEnum, delayBeforeLoggingMs: Int = 2000) {
+ synchronized(clock) {
+ val currentTimeMs = clock.elapsedRealtime()
+ val shouldThrottle =
+ event == lastEventThrottled &&
+ currentTimeMs - lastTimeThrottledMs < delayBeforeLoggingMs
+ lastEventThrottled = event
+ lastTimeThrottledMs = currentTimeMs
+ if (shouldThrottle) {
+ return
+ }
+ }
+ log(event)
+ }
+
/** Logs the given event */
- fun log(event: UiEventLogger.UiEventEnum) {
+ fun log(event: UiEventEnum) {
uiEventLogger.log(event)
}
+ /**
+ * Logs the given event with an integer rank/position value.
+ *
+ * @param event the event to log
+ * @param position the rank or position value that the user interacted with in the UI
+ */
+ fun logWithPosition(event: UiEventEnum, position: Int) {
+ uiEventLogger.logWithPosition(event, /* uid= */ 0, /* packageName= */ null, position)
+ }
+
/** Events regarding interaction with the magnifier settings panel */
enum class MagnificationSettingsEvent constructor(private val id: Int) :
- UiEventLogger.UiEventEnum {
- @UiEvent(doc = "Magnification settings panel opened.")
+ UiEventEnum {
+ @UiEvent(
+ doc =
+ "Magnification settings panel opened. The selection rank is from which " +
+ "magnifier mode it was opened (fullscreen or window)"
+ )
MAGNIFICATION_SETTINGS_PANEL_OPENED(1381),
@UiEvent(doc = "Magnification settings panel closed")
@@ -46,7 +93,14 @@
@UiEvent(doc = "Magnification settings panel edit size save button clicked")
MAGNIFICATION_SETTINGS_SIZE_EDITING_DEACTIVATED(1384),
- @UiEvent(doc = "Magnification settings panel window size selected")
+ @UiEvent(doc = "Magnification settings panel zoom slider changed")
+ MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED(1385),
+
+ @UiEvent(
+ doc =
+ "Magnification settings panel window size selected. The selection rank is " +
+ "which size was selected."
+ )
MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED(1386);
override fun getId(): Int = this.id
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 2a14dc8..8f50af9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
@@ -346,7 +347,10 @@
@Override
public void onSetMagnifierSize(int displayId, int index) {
mHandler.post(() -> onSetMagnifierSizeInternal(displayId, index));
- mA11yLogger.log(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED);
+ mA11yLogger.logWithPosition(
+ MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED,
+ index
+ );
}
@Override
@@ -367,6 +371,9 @@
if (mWindowMagnificationConnectionImpl != null) {
mWindowMagnificationConnectionImpl.onPerformScaleAction(displayId, scale);
}
+ mA11yLogger.logThrottled(
+ MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED
+ );
}
@Override
@@ -377,9 +384,6 @@
@Override
public void onSettingsPanelVisibilityChanged(int displayId, boolean shown) {
mHandler.post(() -> onSettingsPanelVisibilityChangedInternal(displayId, shown));
- mA11yLogger.log(shown
- ? MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED
- : MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_CLOSED);
}
};
@@ -433,8 +437,22 @@
private void onSettingsPanelVisibilityChangedInternal(int displayId, boolean shown) {
final WindowMagnificationController windowMagnificationController =
mMagnificationControllerSupplier.get(displayId);
- if (windowMagnificationController != null && windowMagnificationController.isActivated()) {
- windowMagnificationController.updateDragHandleResourcesIfNeeded(shown);
+ if (windowMagnificationController != null) {
+ boolean isWindowMagnifierActivated = windowMagnificationController.isActivated();
+ if (isWindowMagnifierActivated) {
+ windowMagnificationController.updateDragHandleResourcesIfNeeded(shown);
+ }
+
+ if (shown) {
+ mA11yLogger.logWithPosition(
+ MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED,
+ isWindowMagnifierActivated
+ ? ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
+ : ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
+ );
+ } else {
+ mA11yLogger.log(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_CLOSED);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java
index 7f4e7844..225a2f7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationController.java
@@ -25,7 +25,7 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import com.android.systemui.R;
-import com.android.wm.shell.bubbles.DismissView;
+import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 3f41a76..6ba40d6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -61,7 +61,8 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.bubbles.DismissView;
+import com.android.wm.shell.bubbles.DismissViewUtils;
+import com.android.wm.shell.common.bubbles.DismissView;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import java.lang.annotation.Retention;
@@ -184,6 +185,7 @@
mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage);
mMenuAnimationController.setSpringAnimationsEndAction(this::onSpringAnimationsEndAction);
mDismissView = new DismissView(context);
+ DismissViewUtils.setup(mDismissView);
mDismissAnimationController = new DismissAnimationController(mDismissView, mMenuView);
mDismissAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
index e79b3f4..a910ab5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -34,6 +34,7 @@
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
@@ -48,6 +49,7 @@
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
private val systemClock: SystemClock,
+ private val userTracker: UserTracker,
@Main mainHandler: Handler,
@Background private val backgroundDelayableExecutor: DelayableExecutor
) : SystemUIDialog(context) {
@@ -98,7 +100,8 @@
seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
- val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
+ val currentScale =
+ systemSettings.getFloatForUser(Settings.System.FONT_SCALE, 1.0f, userTracker.userId)
lastProgress.set(fontSizeValueToIndex(currentScale))
seekBarWithIconButtonsView.setProgress(lastProgress.get())
@@ -195,18 +198,25 @@
@WorkerThread
fun updateFontScale() {
- systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[lastProgress.get()])
+ systemSettings.putStringForUser(
+ Settings.System.FONT_SCALE,
+ strEntryValues[lastProgress.get()],
+ userTracker.userId
+ )
}
@WorkerThread
fun updateSecureSettingsIfNeeded() {
if (
- secureSettings.getString(Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED) !=
- ON
- ) {
- secureSettings.putString(
+ secureSettings.getStringForUser(
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
- ON
+ userTracker.userId
+ ) != ON
+ ) {
+ secureSettings.putStringForUser(
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+ ON,
+ userTracker.userId
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index c4ebee2..0530aed 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -77,7 +77,9 @@
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
private val _authenticationMethod =
- MutableStateFlow<AuthenticationMethodModel>(AuthenticationMethodModel.Pin(1234))
+ MutableStateFlow<AuthenticationMethodModel>(
+ AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
+ )
override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
_authenticationMethod.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index dd9dcbe..20e82f7 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -122,14 +122,36 @@
/**
* Attempts to authenticate the user and unlock the device.
*
+ * If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method
+ * supports auto-confirming, and the input's length is at least the code's length. Otherwise,
+ * `null` is returned.
+ *
* @param input The input from the user to try to authenticate with. This can be a list of
* different things, based on the current authentication method.
- * @return `true` if the authentication succeeded and the device is now unlocked; `false`
- * otherwise.
+ * @param tryAutoConfirm `true` if called while the user inputs the code, without an explicit
+ * request to validate.
+ * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
+ * authentication failed, `null` if the check was not performed.
*/
- fun authenticate(input: List<Any>): Boolean {
+ fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
+ val authMethod = this.authenticationMethod.value
+ if (tryAutoConfirm) {
+ if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
+ // Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
+ return null
+ }
+
+ if (input.size < authMethod.code.size) {
+ // Do not attempt to authenticate if the PIN has not yet the required amount of
+ // digits. This intentionally only skip for shorter PINs; if the PIN is longer, the
+ // layer above might have throttled this check, and the PIN should be rejected via
+ // the auth code below.
+ return null
+ }
+ }
+
val isSuccessful =
- when (val authMethod = this.authenticationMethod.value) {
+ when (authMethod) {
is AuthenticationMethodModel.Pin -> input.asCode() == authMethod.code
is AuthenticationMethodModel.Password -> input.asPassword() == authMethod.password
is AuthenticationMethodModel.Pattern -> input.asPattern() == authMethod.coordinates
@@ -180,21 +202,17 @@
* Returns a PIN code from the given list. It's assumed the given list elements are all
* [Int] in the range [0-9].
*/
- private fun List<Any>.asCode(): Long? {
+ private fun List<Any>.asCode(): List<Int>? {
if (isEmpty() || size > DevicePolicyManager.MAX_PASSWORD_LENGTH) {
return null
}
- var code = 0L
- map {
- require(it is Int && it in 0..9) {
- "Pin is required to be Int in range [0..9], but got $it"
- }
- it
+ return map {
+ require(it is Int && it in 0..9) {
+ "Pin is required to be Int in range [0..9], but got $it"
}
- .forEach { integer -> code = code * 10 + integer }
-
- return code
+ it
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
index e4fbf9a..1016b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
@@ -16,6 +16,8 @@
package com.android.systemui.authentication.shared.model
+import androidx.annotation.VisibleForTesting
+
/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
/**
@@ -38,7 +40,16 @@
* In practice, a pin is restricted to 16 decimal digits , see
* [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH]
*/
- data class Pin(val code: Long) : AuthenticationMethodModel(isSecure = true)
+ data class Pin(val code: List<Int>, val autoConfirm: Boolean) :
+ AuthenticationMethodModel(isSecure = true) {
+
+ /** Convenience constructor for tests only. */
+ @VisibleForTesting
+ constructor(
+ code: Long,
+ autoConfirm: Boolean = false
+ ) : this(code.toString(10).map { it - '0' }, autoConfirm) {}
+ }
data class Password(val password: String) : AuthenticationMethodModel(isSecure = true)
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
new file mode 100644
index 0000000..3c74bf4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.back.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.QuickSettingsController
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import javax.inject.Inject
+
+/** Handles requests to go back either from a button or gesture. */
+@SysUISingleton
+class BackActionInteractor
+@Inject
+constructor(
+ private val statusBarStateController: StatusBarStateController,
+ private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+ private val shadeController: ShadeController
+) {
+ private lateinit var shadeViewController: ShadeViewController
+ private lateinit var qsController: QuickSettingsController
+
+ fun setup(qsController: QuickSettingsController, svController: ShadeViewController) {
+ this.qsController = qsController
+ this.shadeViewController = svController
+ }
+
+ fun shouldBackBeHandled(): Boolean {
+ return statusBarStateController.state != StatusBarState.KEYGUARD &&
+ statusBarStateController.state != StatusBarState.SHADE_LOCKED &&
+ !statusBarKeyguardViewManager.isBouncerShowingOverDream
+ }
+
+ fun onBackRequested(): Boolean {
+ if (statusBarKeyguardViewManager.canHandleBackPressed()) {
+ statusBarKeyguardViewManager.onBackPressed()
+ return true
+ }
+ if (qsController.isCustomizing) {
+ qsController.closeQsCustomizer()
+ return true
+ }
+ if (qsController.expanded) {
+ shadeViewController.animateCollapseQs(false)
+ return true
+ }
+ if (shadeViewController.closeUserSwitcherIfOpen()) {
+ return true
+ }
+ if (shouldBackBeHandled()) {
+ if (shadeViewController.canBeCollapsed()) {
+ // this is the Shade dismiss animation, so make sure QQS closes when it ends.
+ shadeViewController.onBackPressed()
+ shadeController.animateCollapseShade()
+ }
+ return true
+ }
+ return false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 7f70685..d8348ed 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -374,7 +374,6 @@
if (Utils.isBiometricAllowed(config.mPromptInfo)) {
mPromptSelectorInteractorProvider.get().useBiometricsForAuthentication(
config.mPromptInfo,
- config.mRequireConfirmation,
config.mUserId,
config.mOperationId,
new BiometricModalities(fpProps, faceProps));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index e58876a..76e48e9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -1057,8 +1057,16 @@
}
private String getNotRecognizedString(@Modality int modality) {
- return mContext.getString(modality == TYPE_FACE
- ? R.string.biometric_face_not_recognized : R.string.biometric_not_recognized);
+ final int messageRes;
+ final int userId = mCurrentDialogArgs.argi1;
+ if (isFaceAuthEnrolled(userId) && isFingerprintEnrolled(userId)) {
+ messageRes = modality == TYPE_FACE
+ ? R.string.biometric_face_not_recognized
+ : R.string.fingerprint_error_not_match;
+ } else {
+ messageRes = R.string.biometric_not_recognized;
+ }
+ return mContext.getString(messageRes);
}
private String getErrorString(@Modality int modality, int error, int vendorCode) {
@@ -1216,8 +1224,11 @@
final PromptInfo promptInfo = (PromptInfo) args.arg1;
final int[] sensorIds = (int[]) args.arg3;
+
+ // TODO(b/251476085): remove these unused parameters (replaced with SSOT elsewhere)
final boolean credentialAllowed = (boolean) args.arg4;
final boolean requireConfirmation = (boolean) args.arg5;
+
final int userId = args.argi1;
final String opPackageName = (String) args.arg6;
final long operationId = args.argl1;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
index b72801d..5218537 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
@@ -16,11 +16,13 @@
@Main private val mainExecutor: Executor,
) {
private var action: Action? = null
+ private var panelState: Int = -1
@MainThread
fun enable(onPanelInteraction: Runnable) {
if (action == null) {
action = Action(onPanelInteraction)
+ shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
} else {
Log.e(TAG, "Already enabled")
@@ -32,6 +34,8 @@
if (action != null) {
Log.i(TAG, "Disable dectector")
action = null
+ panelState = -1
+ shadeExpansionStateManager.removeStateListener(this::onPanelStateChanged)
shadeExpansionStateManager.removeExpansionListener(this::onPanelExpansionChanged)
}
}
@@ -40,13 +44,34 @@
private fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) =
mainExecutor.execute {
action?.let {
- if (event.tracking || (event.expanded && event.fraction > 0)) {
- Log.i(TAG, "Detected panel interaction, event: $event")
+ if (event.tracking || (event.expanded && event.fraction > 0 && panelState == 1)) {
+ Log.i(TAG, "onPanelExpansionChanged, event: $event")
it.onPanelInteraction.run()
disable()
}
}
}
+
+ @AnyThread
+ private fun onPanelStateChanged(state: Int) =
+ mainExecutor.execute {
+ // When device owner set screen lock type as Swipe, and install work profile with
+ // pin/pattern/password & fingerprint or face, if work profile allow user to verify
+ // by BP, it is possible that BP will be displayed when keyguard is closing, in this
+ // case event.expanded = true and event.fraction > 0, so BP will be closed, adding
+ // panel state into consideration is workaround^2, this workaround works because
+ // onPanelStateChanged is earlier than onPanelExpansionChanged
+
+ // we don't want to close BP in below case
+ //
+ // | Action | tracking | expanded | fraction | panelState |
+ // | HeadsUp | NA | NA | NA | 1 |
+ // | b/285111529 | false | true | > 0 | 2 |
+
+ // Note: HeadsUp behavior was changed, so we can't got onPanelExpansionChanged now
+ panelState = state
+ Log.i(TAG, "onPanelStateChanged, state: $state")
+ }
}
private data class Action(val onPanelInteraction: Runnable)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a91499a..0dc7974 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -356,7 +356,8 @@
UdfpsController.this.mAlternateTouchProvider.onUiReady();
} else {
final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
- UdfpsController.this.mFingerprintManager.onUiReady(requestId, sensorId);
+ UdfpsController.this.mFingerprintManager.onUdfpsUiEvent(
+ FingerprintManager.UDFPS_UI_READY, requestId, sensorId);
}
}
}
@@ -956,6 +957,10 @@
mOnFingerDown = false;
mAttemptedToDismissKeyguard = false;
mOrientationListener.enable();
+ if (mFingerprintManager != null) {
+ mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
+ overlay.getRequestId(), mSensorProps.sensorId);
+ }
} else {
Log.v(TAG, "showUdfpsOverlay | the overlay is already showing");
}
@@ -1097,7 +1102,8 @@
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
});
} else {
- mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
+ mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_READY, requestId,
+ mSensorProps.sensorId);
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index ddf1457..a5e846a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -17,6 +17,8 @@
package com.android.systemui.biometrics.dagger
import com.android.settingslib.udfps.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.FaceSettingsRepository
+import com.android.systemui.biometrics.data.repository.FaceSettingsRepositoryImpl
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
import com.android.systemui.biometrics.data.repository.PromptRepository
@@ -47,6 +49,10 @@
@Binds
@SysUISingleton
+ fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
+
+ @Binds
+ @SysUISingleton
fun biometricPromptRepository(impl: PromptRepositoryImpl): PromptRepository
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepository.kt
new file mode 100644
index 0000000..3d5ed82
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepository.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
+
+import android.os.Handler
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.settings.SecureSettings
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+
+/**
+ * Repository for the global state of users Face Unlock preferences.
+ *
+ * Largely a wrapper around [SecureSettings]'s proxy to Settings.Secure.
+ */
+interface FaceSettingsRepository {
+
+ /** Get Settings for the given user [id]. */
+ fun forUser(id: Int?): FaceUserSettingsRepository
+}
+
+@SysUISingleton
+class FaceSettingsRepositoryImpl
+@Inject
+constructor(
+ @Main private val mainHandler: Handler,
+ private val secureSettings: SecureSettings,
+) : FaceSettingsRepository {
+
+ private val userSettings = ConcurrentHashMap<Int, FaceUserSettingsRepository>()
+
+ override fun forUser(id: Int?): FaceUserSettingsRepository =
+ if (id != null) {
+ userSettings.computeIfAbsent(id) { _ ->
+ FaceUserSettingsRepositoryImpl(id, mainHandler, secureSettings).also { repo ->
+ repo.start()
+ }
+ }
+ } else {
+ FaceUserSettingsRepositoryImpl.Empty
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceUserSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceUserSettingsRepository.kt
new file mode 100644
index 0000000..68c4a10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FaceUserSettingsRepository.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
+
+import android.database.ContentObserver
+import android.os.Handler
+import android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.settings.SecureSettings
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flowOf
+
+/** Settings for a user. */
+interface FaceUserSettingsRepository {
+ /** The user's id. */
+ val userId: Int
+
+ /** If BiometricPrompt should always require confirmation (overrides app's preference). */
+ val alwaysRequireConfirmationInApps: Flow<Boolean>
+}
+
+class FaceUserSettingsRepositoryImpl(
+ override val userId: Int,
+ @Main private val mainHandler: Handler,
+ private val secureSettings: SecureSettings,
+) : FaceUserSettingsRepository {
+
+ /** Indefinitely subscribe to user preference changes. */
+ fun start() {
+ watch(
+ FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+ _alwaysRequireConfirmationInApps,
+ )
+ }
+
+ private var _alwaysRequireConfirmationInApps = MutableStateFlow(false)
+ override val alwaysRequireConfirmationInApps: Flow<Boolean> =
+ _alwaysRequireConfirmationInApps.asStateFlow()
+
+ /** Defaults to use when no user is specified. */
+ object Empty : FaceUserSettingsRepository {
+ override val userId = -1
+ override val alwaysRequireConfirmationInApps = flowOf(false)
+ }
+
+ private fun watch(
+ key: String,
+ toUpdate: MutableStateFlow<Boolean>,
+ defaultValue: Boolean = false,
+ ) = secureSettings.watch(userId, mainHandler, key, defaultValue) { v -> toUpdate.value = v }
+}
+
+private fun SecureSettings.watch(
+ userId: Int,
+ handler: Handler,
+ key: String,
+ defaultValue: Boolean = false,
+ onChange: (Boolean) -> Unit,
+) {
+ fun fetch(): Boolean = getIntForUser(key, if (defaultValue) 1 else 0, userId) > 0
+
+ registerContentObserverForUser(
+ key,
+ false /* notifyForDescendants */,
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean) = onChange(fetch())
+ },
+ userId
+ )
+
+ onChange(fetch())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
index b4dc272..b35fbbc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
import android.hardware.biometrics.PromptInfo
@@ -12,6 +28,10 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
/**
* A repository for the global state of BiometricPrompt.
@@ -40,7 +60,7 @@
*
* Note: overlaps/conflicts with [PromptInfo.isConfirmationRequested], which needs clean up.
*/
- val isConfirmationRequired: StateFlow<Boolean>
+ val isConfirmationRequired: Flow<Boolean>
/** Update the prompt configuration, which should be set before [isShowing]. */
fun setPrompt(
@@ -48,7 +68,6 @@
userId: Int,
gatekeeperChallenge: Long?,
kind: PromptKind,
- requireConfirmation: Boolean = false,
)
/** Unset the prompt info. */
@@ -56,8 +75,12 @@
}
@SysUISingleton
-class PromptRepositoryImpl @Inject constructor(private val authController: AuthController) :
- PromptRepository {
+class PromptRepositoryImpl
+@Inject
+constructor(
+ private val faceSettings: FaceSettingsRepository,
+ private val authController: AuthController,
+) : PromptRepository {
override val isShowing: Flow<Boolean> = conflatedCallbackFlow {
val callback =
@@ -85,21 +108,30 @@
private val _kind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.Biometric())
override val kind = _kind.asStateFlow()
- private val _isConfirmationRequired: MutableStateFlow<Boolean> = MutableStateFlow(false)
- override val isConfirmationRequired = _isConfirmationRequired.asStateFlow()
+ private val _faceSettings =
+ _userId.map { id -> faceSettings.forUser(id) }.distinctUntilChanged()
+ private val _faceSettingAlwaysRequireConfirmation =
+ _faceSettings.flatMapLatest { it.alwaysRequireConfirmationInApps }.distinctUntilChanged()
+
+ private val _isConfirmationRequired = _promptInfo.map { it?.isConfirmationRequested ?: false }
+ override val isConfirmationRequired =
+ combine(_isConfirmationRequired, _faceSettingAlwaysRequireConfirmation) {
+ appRequiresConfirmation,
+ forceRequireConfirmation ->
+ forceRequireConfirmation || appRequiresConfirmation
+ }
+ .distinctUntilChanged()
override fun setPrompt(
promptInfo: PromptInfo,
userId: Int,
gatekeeperChallenge: Long?,
kind: PromptKind,
- requireConfirmation: Boolean,
) {
_kind.value = kind
_userId.value = userId
_challenge.value = gatekeeperChallenge
_promptInfo.value = promptInfo
- _isConfirmationRequired.value = requireConfirmation
}
override fun unsetPrompt() {
@@ -107,7 +139,6 @@
_userId.value = null
_challenge.value = null
_kind.value = PromptKind.Biometric()
- _isConfirmationRequired.value = false
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index e6e07f9..be99dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -59,13 +59,15 @@
*/
val credentialKind: Flow<PromptKind>
- /** If the API caller requested explicit confirmation after successful authentication. */
- val isConfirmationRequested: Flow<Boolean>
+ /**
+ * If the API caller or the user's personal preferences require explicit confirmation after
+ * successful authentication.
+ */
+ val isConfirmationRequired: Flow<Boolean>
/** Use biometrics for authentication. */
fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
- requireConfirmation: Boolean,
userId: Int,
challenge: Long,
modalities: BiometricModalities,
@@ -114,10 +116,8 @@
}
}
- override val isConfirmationRequested: Flow<Boolean> =
- promptRepository.promptInfo
- .map { info -> info?.isConfirmationRequested ?: false }
- .distinctUntilChanged()
+ override val isConfirmationRequired: Flow<Boolean> =
+ promptRepository.isConfirmationRequired.distinctUntilChanged()
override val isCredentialAllowed: Flow<Boolean> =
promptRepository.promptInfo
@@ -142,7 +142,6 @@
override fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
- requireConfirmation: Boolean,
userId: Int,
challenge: Long,
modalities: BiometricModalities
@@ -152,7 +151,6 @@
userId = userId,
gatekeeperChallenge = challenge,
kind = PromptKind.Biometric(modalities),
- requireConfirmation = requireConfirmation,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 34c8d9f..6a7431e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -158,7 +158,7 @@
view.updateFingerprintAffordanceSize(iconController)
}
if (iconController is HackyCoexIconController) {
- iconController.faceMode = !viewModel.isConfirmationRequested.first()
+ iconController.faceMode = !viewModel.isConfirmationRequired.first()
}
// the icon controller must be created before this happens for the legacy
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 0fffee6..05a5362 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -61,8 +61,11 @@
/** If the user has successfully authenticated and confirmed (when explicitly required). */
val isAuthenticated: Flow<PromptAuthState> = _isAuthenticated.asStateFlow()
- /** If the API caller requested explicit confirmation after successful authentication. */
- val isConfirmationRequested: Flow<Boolean> = interactor.isConfirmationRequested
+ /**
+ * If the API caller or the user's personal preferences require explicit confirmation after
+ * successful authentication.
+ */
+ val isConfirmationRequired: Flow<Boolean> = interactor.isConfirmationRequired
/** The kind of credential the user has. */
val credentialKind: Flow<PromptKind> = interactor.credentialKind
@@ -91,7 +94,7 @@
_forceLargeSize,
_forceMediumSize,
modalities,
- interactor.isConfirmationRequested,
+ interactor.isConfirmationRequired,
fingerprintStartMode,
) { forceLarge, forceMedium, modalities, confirmationRequired, fpStartMode ->
when {
@@ -383,7 +386,7 @@
private suspend fun needsExplicitConfirmation(modality: BiometricModality): Boolean {
val availableModalities = modalities.first()
- val confirmationRequested = interactor.isConfirmationRequested.first()
+ val confirmationRequested = interactor.isConfirmationRequired.first()
if (availableModalities.hasFaceAndFingerprint) {
// coex only needs confirmation when face is successful, unless it happens on the
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index c833def..256c635 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -149,19 +149,28 @@
* If the input is correct, the device will be unlocked and the lock screen and bouncer will be
* dismissed and hidden.
*
+ * If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method
+ * supports auto-confirming, and the input's length is at least the code's length. Otherwise,
+ * `null` is returned.
+ *
* @param input The input from the user to try to authenticate with. This can be a list of
* different things, based on the current authentication method.
- * @return `true` if the authentication succeeded and the device is now unlocked; `false`
- * otherwise.
+ * @param tryAutoConfirm `true` if called while the user inputs the code, without an explicit
+ * request to validate.
+ * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
+ * authentication failed, `null` if the check was not performed.
*/
fun authenticate(
input: List<Any>,
- ): Boolean {
+ tryAutoConfirm: Boolean = false,
+ ): Boolean? {
if (repository.throttling.value != null) {
return false
}
- val isAuthenticated = authenticationInteractor.authenticate(input)
+ val isAuthenticated =
+ authenticationInteractor.authenticate(input, tryAutoConfirm) ?: return null
+
val failedAttempts = authenticationInteractor.failedAuthenticationAttempts.value
when {
isAuthenticated -> {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 55929b5..0146e40 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -50,7 +50,7 @@
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
fun onAuthenticateKeyPressed() {
- if (!interactor.authenticate(password.value.toCharArray().toList())) {
+ if (interactor.authenticate(password.value.toCharArray().toList()) != true) {
showFailureAnimation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index d9ef75d..700703e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -153,9 +153,8 @@
/** Notifies that the user has ended the drag gesture across the dot grid. */
fun onDragEnd() {
- val isSuccessfullyAuthenticated =
- interactor.authenticate(_selectedDots.value.map { it.toCoordinate() })
- if (!isSuccessfullyAuthenticated) {
+ val pattern = _selectedDots.value.map { it.toCoordinate() }
+ if (interactor.authenticate(pattern) != true) {
showFailureAnimation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 94d3d19..1944c74 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -16,14 +16,19 @@
package com.android.systemui.bouncer.ui.viewmodel
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
- private val applicationScope: CoroutineScope,
+ applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -34,6 +39,42 @@
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
+ /** The length of the hinted PIN, or null if pin length hint should not be shown. */
+ val hintedPinLength: StateFlow<Int?> =
+ interactor.authenticationMethod
+ .map { authMethod -> computeHintedPinLength(authMethod) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = computeHintedPinLength(interactor.authenticationMethod.value),
+ )
+
+ /** Appearance of the backspace button. */
+ val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
+ combine(interactor.authenticationMethod, mutablePinEntries) { authMethod, enteredPin ->
+ computeBackspaceButtonAppearance(authMethod, enteredPin)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue =
+ computeBackspaceButtonAppearance(
+ interactor.authenticationMethod.value,
+ mutablePinEntries.value
+ ),
+ )
+
+ /** Appearance of the confirm button. */
+ val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
+ interactor.authenticationMethod
+ .map { authMethod -> computeConfirmButtonAppearance(authMethod) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue =
+ computeConfirmButtonAppearance(interactor.authenticationMethod.value),
+ )
+
/** Notifies that the UI has been shown to the user. */
fun onShown() {
interactor.resetMessage()
@@ -46,6 +87,8 @@
}
mutablePinEntries.value += EnteredKey(input)
+
+ tryAuthenticate(useAutoConfirm = true)
}
/** Notifies that the user clicked the backspace button. */
@@ -63,14 +106,72 @@
/** Notifies that the user clicked the "enter" button. */
fun onAuthenticateButtonClicked() {
- if (!interactor.authenticate(mutablePinEntries.value.map { it.input })) {
+ tryAuthenticate(useAutoConfirm = false)
+ }
+
+ private fun tryAuthenticate(useAutoConfirm: Boolean) {
+ val pinCode = mutablePinEntries.value.map { it.input }
+ val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return
+
+ if (!isSuccess) {
showFailureAnimation()
}
mutablePinEntries.value = emptyList()
}
+
+ private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel): Boolean {
+ return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true
+ }
+
+ private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel): Int? {
+ if (!isAutoConfirmEnabled(authMethodModel)) return null
+
+ return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size
+ }
+
+ private fun computeHintedPinLength(authMethodModel: AuthenticationMethodModel): Int? {
+ // Hinting is enabled for 6-digit codes only
+ return autoConfirmPinLength(authMethodModel).takeIf { it == HINTING_PASSCODE_LENGTH }
+ }
+
+ private fun computeBackspaceButtonAppearance(
+ authMethodModel: AuthenticationMethodModel,
+ enteredPin: List<EnteredKey>
+ ): ActionButtonAppearance {
+ val isAutoConfirmEnabled = isAutoConfirmEnabled(authMethodModel)
+ val isEmpty = enteredPin.isEmpty()
+
+ return when {
+ isAutoConfirmEnabled && isEmpty -> ActionButtonAppearance.Hidden
+ isAutoConfirmEnabled -> ActionButtonAppearance.Subtle
+ else -> ActionButtonAppearance.Shown
+ }
+ }
+ private fun computeConfirmButtonAppearance(
+ authMethodModel: AuthenticationMethodModel
+ ): ActionButtonAppearance {
+ return if (isAutoConfirmEnabled(authMethodModel)) {
+ ActionButtonAppearance.Hidden
+ } else {
+ ActionButtonAppearance.Shown
+ }
+ }
}
+/** Appearance of pin-pad action buttons. */
+enum class ActionButtonAppearance {
+ /** Button must not be shown. */
+ Hidden,
+ /** Button is shown, but with no background to make it less prominent. */
+ Subtle,
+ /** Button is shown. */
+ Shown,
+}
+
+/** Auto-confirm passcodes of exactly 6 digits show a length hint, see http://shortn/_IXlmSNbDh6 */
+private const val HINTING_PASSCODE_LENGTH = 6
+
private var nextSequenceNumber = 1
/**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index b2bcb05..25ccc16 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -396,6 +396,7 @@
|| mDataProvider.isDocked()
|| mAccessibilityManager.isTouchExplorationEnabled()
|| mDataProvider.isA11yAction()
+ || mDataProvider.isFromTrackpad()
|| (mFeatureFlags.isEnabled(Flags.FALSING_OFF_FOR_UNFOLDED)
&& mDataProvider.isUnfolded());
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index d6c85fb..809d5b2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -261,6 +261,16 @@
return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY();
}
+ public boolean isFromTrackpad() {
+ if (mRecentMotionEvents.isEmpty()) {
+ return false;
+ }
+
+ int classification = mRecentMotionEvents.get(0).getClassification();
+ return classification == MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE
+ || classification == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
+ }
+
private void recalculateData() {
if (!mDirty) {
return;
@@ -343,7 +353,9 @@
motionEvent.getDeviceId(),
motionEvent.getEdgeFlags(),
motionEvent.getSource(),
- motionEvent.getFlags()
+ motionEvent.getDisplayId(),
+ motionEvent.getFlags(),
+ motionEvent.getClassification()
));
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 757ebf4..ffd836b 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -18,6 +18,7 @@
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
+
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_SHOWN;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
@@ -33,6 +34,7 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
+import static com.android.systemui.flags.Flags.CLIPBOARD_SHARED_TRANSITIONS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +49,7 @@
import android.net.Uri;
import android.os.Looper;
import android.provider.DeviceConfig;
+import android.util.Log;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InputMonitor;
@@ -54,6 +57,7 @@
import android.view.WindowInsets;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
@@ -73,7 +77,8 @@
/**
* Controls state and UI for the overlay that appears when something is added to the clipboard
*/
-public class ClipboardOverlayController implements ClipboardListener.ClipboardOverlay {
+public class ClipboardOverlayController implements ClipboardListener.ClipboardOverlay,
+ ClipboardOverlayView.ClipboardOverlayCallbacks {
private static final String TAG = "ClipboardOverlayCtrlr";
/** Constants for screenshot/copy deconflicting */
@@ -92,6 +97,7 @@
private final FeatureFlags mFeatureFlags;
private final Executor mBgExecutor;
private final ClipboardImageLoader mClipboardImageLoader;
+ private final ClipboardTransitionExecutor mTransitionExecutor;
private final ClipboardOverlayView mView;
@@ -179,10 +185,12 @@
ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
ClipboardImageLoader clipboardImageLoader,
+ ClipboardTransitionExecutor transitionExecutor,
UiEventLogger uiEventLogger) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mClipboardImageLoader = clipboardImageLoader;
+ mTransitionExecutor = transitionExecutor;
mClipboardLogger = new ClipboardLogger(uiEventLogger);
@@ -200,7 +208,11 @@
mClipboardUtils = clipboardUtils;
mBgExecutor = bgExecutor;
- mView.setCallbacks(mClipboardCallbacks);
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ mView.setCallbacks(this);
+ } else {
+ mView.setCallbacks(mClipboardCallbacks);
+ }
mWindow.withWindowAttached(() -> {
mWindow.setContentView(mView);
@@ -209,16 +221,24 @@
});
mTimeoutHandler.setOnTimeoutRunnable(() -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
- animateOut();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_TIMED_OUT);
+ } else {
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
+ animateOut();
+ }
});
mCloseDialogsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
- animateOut();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
+ } else {
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
+ animateOut();
+ }
}
}
};
@@ -229,8 +249,12 @@
@Override
public void onReceive(Context context, Intent intent) {
if (SCREENSHOT_ACTION.equals(intent.getAction())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
- animateOut();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
+ } else {
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
+ animateOut();
+ }
}
}
};
@@ -457,8 +481,12 @@
remoteAction.ifPresent(action -> {
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
mView.post(() -> mView.setActionChip(action, () -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
- animateOut();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_ACTION_TAPPED);
+ } else {
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
+ animateOut();
+ }
}));
});
}
@@ -500,8 +528,12 @@
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (!mView.isInTouchRegion(
(int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
- animateOut();
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
+ } else {
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
+ animateOut();
+ }
}
}
}
@@ -551,12 +583,16 @@
mEnterAnimator.start();
}
+ private void finish(ClipboardOverlayEvent event) {
+ finish(event, null);
+ }
+
private void animateOut() {
if (mExitAnimator != null && mExitAnimator.isRunning()) {
return;
}
- Animator anim = mView.getExitAnimation();
- anim.addListener(new AnimatorListenerAdapter() {
+ mExitAnimator = mView.getExitAnimation();
+ mExitAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
@@ -573,8 +609,47 @@
}
}
});
- mExitAnimator = anim;
- anim.start();
+ mExitAnimator.start();
+ }
+
+ private void finish(ClipboardOverlayEvent event, @Nullable Intent intent) {
+ if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ return;
+ }
+ mExitAnimator = mView.getExitAnimation();
+ mExitAnimator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!mCancelled) {
+ mClipboardLogger.logSessionComplete(event);
+ if (intent != null) {
+ mContext.startActivity(intent);
+ }
+ hideImmediate();
+ }
+ }
+ });
+ mExitAnimator.start();
+ }
+
+ private void finishWithSharedTransition(ClipboardOverlayEvent event, Intent intent) {
+ if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ return;
+ }
+ mClipboardLogger.logSessionComplete(event);
+ mExitAnimator = mView.getFadeOutAnimation();
+ mExitAnimator.start();
+ mTransitionExecutor.startSharedTransition(
+ mWindow, mView.getPreview(), intent, this::hideImmediate);
}
void hideImmediate() {
@@ -613,6 +688,76 @@
mClipboardLogger.reset();
}
+ @Override
+ public void onDismissButtonTapped() {
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
+ }
+ }
+
+ @Override
+ public void onRemoteCopyButtonTapped() {
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ finish(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED,
+ IntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
+ }
+ }
+
+ @Override
+ public void onShareButtonTapped() {
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ if (mClipboardModel.getType() != ClipboardModel.Type.OTHER) {
+ finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED,
+ IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
+ }
+ }
+ }
+
+ @Override
+ public void onPreviewTapped() {
+ if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
+ switch (mClipboardModel.getType()) {
+ case TEXT:
+ finish(CLIPBOARD_OVERLAY_EDIT_TAPPED,
+ IntentCreator.getTextEditorIntent(mContext));
+ break;
+ case IMAGE:
+ finishWithSharedTransition(CLIPBOARD_OVERLAY_EDIT_TAPPED,
+ IntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
+ break;
+ default:
+ Log.w(TAG, "Got preview tapped callback for non-editable type "
+ + mClipboardModel.getType());
+ }
+ }
+ }
+
+ @Override
+ public void onMinimizedViewTapped() {
+ animateFromMinimized();
+ }
+
+ @Override
+ public void onInteraction() {
+ if (!mClipboardModel.isRemote()) {
+ mTimeoutHandler.resetTimeout();
+ }
+ }
+
+ @Override
+ public void onSwipeDismissInitiated(Animator animator) {
+ if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ mExitAnimator.cancel();
+ }
+ mExitAnimator = animator;
+ mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
+ }
+
+ @Override
+ public void onDismissComplete() {
+ hideImmediate();
+ }
+
static class ClipboardLogger {
private final UiEventLogger mUiEventLogger;
private String mClipSource;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index 28c57d3..a76d2ea 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -254,6 +254,10 @@
});
}
+ View getPreview() {
+ return mClipboardPreview;
+ }
+
void showImagePreview(@Nullable Bitmap thumbnail) {
if (thumbnail == null) {
mHiddenPreview.setText(mContext.getString(R.string.clipboard_text_hidden));
@@ -368,6 +372,19 @@
return enterAnim;
}
+ Animator getFadeOutAnimation() {
+ ValueAnimator alphaAnim = ValueAnimator.ofFloat(1, 0);
+ alphaAnim.addUpdateListener(animation -> {
+ float alpha = (float) animation.getAnimatedValue();
+ mActionContainer.setAlpha(alpha);
+ mActionContainerBackground.setAlpha(alpha);
+ mPreviewBorder.setAlpha(alpha);
+ mDismissButton.setAlpha(alpha);
+ });
+ alphaAnim.setDuration(300);
+ return alphaAnim;
+ }
+
Animator getExitAnimation() {
TimeInterpolator linearInterpolator = new LinearInterpolator();
TimeInterpolator scaleInterpolator = new PathInterpolator(.3f, 0, 1f, 1f);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt
new file mode 100644
index 0000000..0b8e83e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.clipboardoverlay
+
+import android.app.ActivityOptions
+import android.app.ExitTransitionCoordinator
+import android.content.Context
+import android.content.Intent
+import android.os.RemoteException
+import android.util.Log
+import android.util.Pair
+import android.view.IRemoteAnimationFinishedCallback
+import android.view.IRemoteAnimationRunner
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.View
+import android.view.Window
+import android.view.WindowManagerGlobal
+import com.android.internal.app.ChooserActivity
+import com.android.systemui.settings.DisplayTracker
+import javax.inject.Inject
+
+class ClipboardTransitionExecutor
+@Inject
+constructor(val context: Context, val displayTracker: DisplayTracker) {
+ fun startSharedTransition(window: Window, view: View, intent: Intent, onReady: Runnable) {
+ val transition: Pair<ActivityOptions, ExitTransitionCoordinator> =
+ ActivityOptions.startSharedElementAnimation(
+ window,
+ object : ExitTransitionCoordinator.ExitTransitionCallbacks {
+ override fun isReturnTransitionAllowed(): Boolean {
+ return false
+ }
+
+ override fun hideSharedElements() {
+ onReady.run()
+ }
+
+ override fun onFinish() {}
+ },
+ null,
+ Pair.create(view, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)
+ )
+ transition.second.startExit()
+ context.startActivity(intent, transition.first.toBundle())
+ val runner = RemoteAnimationAdapter(NULL_ACTIVITY_TRANSITION, 0, 0)
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .overridePendingAppTransitionRemote(runner, displayTracker.defaultDisplayId)
+ } catch (e: Exception) {
+ Log.e(TAG, "Error overriding clipboard app transition", e)
+ }
+ }
+
+ private val TAG: String = "ClipboardTransitionExec"
+
+ /**
+ * This is effectively a no-op, but we need something non-null to pass in, in order to
+ * successfully override the pending activity entrance animation.
+ */
+ private val NULL_ACTIVITY_TRANSITION: IRemoteAnimationRunner.Stub =
+ object : IRemoteAnimationRunner.Stub() {
+ override fun onAnimationStart(
+ transit: Int,
+ apps: Array<RemoteAnimationTarget>,
+ wallpapers: Array<RemoteAnimationTarget>,
+ nonApps: Array<RemoteAnimationTarget>,
+ finishedCallback: IRemoteAnimationFinishedCallback
+ ) {
+ try {
+ finishedCallback.onAnimationFinished()
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Error finishing screenshot remote animation", e)
+ }
+ }
+
+ override fun onAnimationCancelled() {}
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 4173bdc..b15c60e 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -24,6 +24,9 @@
import com.android.systemui.multishade.ui.viewmodel.MultiShadeViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import com.android.systemui.util.time.SystemClock
/**
@@ -66,4 +69,11 @@
viewModel: MultiShadeViewModel,
clock: SystemClock,
): View
+
+ /** Create a [View] to represent [viewModel] on screen. */
+ fun createSceneContainerView(
+ context: Context,
+ viewModel: SceneContainerViewModel,
+ sceneByKey: Map<SceneKey, Scene>,
+ ): View
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index a90980f..5493cea 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -18,6 +18,7 @@
import com.android.systemui.globalactions.ShutdownUiModule;
import com.android.systemui.keyguard.CustomizationProvider;
+import com.android.systemui.scene.startable.SceneContainerStartableModule;
import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -33,6 +34,7 @@
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
ShutdownUiModule.class,
+ SceneContainerStartableModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUICoreStartableModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 2262d8a..f68bd49 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -40,7 +40,6 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.rotationlock.RotationLockModule;
-import com.android.systemui.scene.SceneContainerFrameworkModule;
import com.android.systemui.screenshot.ReferenceScreenshotModule;
import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -104,7 +103,6 @@
QSModule.class,
ReferenceScreenshotModule.class,
RotationLockModule.class,
- SceneContainerFrameworkModule.class,
StatusBarEventsModule.class,
StartCentralSurfacesModule.class,
VolumeModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 52355f3..d82bf58 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -16,7 +16,6 @@
package com.android.systemui.dagger;
-import com.android.keyguard.clock.ClockOptionsProvider;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.CoreStartable;
import com.android.systemui.Dependency;
@@ -252,10 +251,5 @@
/**
* Member injection into the supplied argument.
*/
- void inject(ClockOptionsProvider clockOptionsProvider);
-
- /**
- * Member injection into the supplied argument.
- */
void inject(PeopleProvider peopleProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 9eb85df..3954959 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -23,7 +23,6 @@
import androidx.annotation.Nullable;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.keyguard.clock.ClockInfoModule;
import com.android.keyguard.dagger.ClockRegistryModule;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
@@ -38,6 +37,7 @@
import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.biometrics.dagger.UdfpsModule;
+import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
import com.android.systemui.common.ui.data.repository.CommonRepositoryModule;
@@ -52,7 +52,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.keyboard.KeyboardModule;
-import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.log.dagger.MonitorLog;
import com.android.systemui.log.table.TableLogBuffer;
@@ -73,6 +72,7 @@
import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.retail.dagger.RetailModeModule;
+import com.android.systemui.scene.SceneContainerFrameworkModule;
import com.android.systemui.screenrecord.ScreenRecordModule;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
@@ -87,6 +87,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.connectivity.ConnectivityModule;
+import com.android.systemui.statusbar.disableflags.dagger.DisableFlagsModule;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -159,7 +160,6 @@
BiometricsModule.class,
BouncerViewModule.class,
ClipboardOverlayModule.class,
- ClockInfoModule.class,
ClockRegistryModule.class,
CommonRepositoryModule.class,
ConnectivityModule.class,
@@ -167,6 +167,7 @@
DreamModule.class,
ControlsModule.class,
DemoModeModule.class,
+ DisableFlagsModule.class,
FalsingModule.class,
FlagsModule.class,
SystemPropertiesFlagsModule.class,
@@ -185,6 +186,7 @@
QRCodeScannerModule.class,
QSFragmentStartableModule.class,
RetailModeModule.class,
+ SceneContainerFrameworkModule.class,
ScreenshotModule.class,
SensorModule.class,
SecurityRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/decor/DebugRoundedCornerDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/DebugRoundedCornerDelegate.kt
new file mode 100644
index 0000000..4069bc7d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/DebugRoundedCornerDelegate.kt
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.decor
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.util.Size
+import java.io.PrintWriter
+
+/**
+ * Rounded corner delegate that handles incoming debug commands and can convert them to path
+ * drawables to be shown instead of the system-defined rounded corners.
+ *
+ * These debug corners are expected to supersede the system-defined corners
+ */
+class DebugRoundedCornerDelegate : RoundedCornerResDelegate {
+ override var hasTop: Boolean = false
+ private set
+ override var topRoundedDrawable: Drawable? = null
+ private set
+ override var topRoundedSize: Size = Size(0, 0)
+ private set
+
+ override var hasBottom: Boolean = false
+ private set
+ override var bottomRoundedDrawable: Drawable? = null
+ private set
+ override var bottomRoundedSize: Size = Size(0, 0)
+ private set
+
+ override var physicalPixelDisplaySizeRatio: Float = 1f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ reloadMeasures()
+ }
+
+ var color: Int = Color.RED
+ set(value) {
+ if (field == value) {
+ return
+ }
+
+ field = value
+ paint.color = field
+ }
+
+ var paint =
+ Paint().apply {
+ color = Color.RED
+ style = Paint.Style.FILL
+ }
+
+ override fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
+ // nop -- debug corners draw the same on every display
+ }
+
+ fun applyNewDebugCorners(
+ topCorner: DebugRoundedCornerModel,
+ bottomCorner: DebugRoundedCornerModel,
+ ) {
+ hasTop = true
+ topRoundedDrawable = topCorner.toPathDrawable(paint)
+ topRoundedSize = topCorner.size()
+
+ hasBottom = true
+ bottomRoundedDrawable = bottomCorner.toPathDrawable(paint)
+ bottomRoundedSize = bottomCorner.size()
+ }
+
+ /**
+ * Remove accumulated debug state by clearing out the drawables and setting [hasTop] and
+ * [hasBottom] to false.
+ */
+ fun removeDebugState() {
+ hasTop = false
+ topRoundedDrawable = null
+ topRoundedSize = Size(0, 0)
+
+ hasBottom = false
+ bottomRoundedDrawable = null
+ bottomRoundedSize = Size(0, 0)
+ }
+
+ /**
+ * Scaling here happens when the display resolution is changed. This logic is exactly the same
+ * as in [RoundedCornerResDelegateImpl]
+ */
+ private fun reloadMeasures() {
+ topRoundedDrawable?.let { topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight) }
+ bottomRoundedDrawable?.let {
+ bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
+ }
+
+ if (physicalPixelDisplaySizeRatio != 1f) {
+ if (topRoundedSize.width != 0) {
+ topRoundedSize =
+ Size(
+ (physicalPixelDisplaySizeRatio * topRoundedSize.width + 0.5f).toInt(),
+ (physicalPixelDisplaySizeRatio * topRoundedSize.height + 0.5f).toInt()
+ )
+ }
+ if (bottomRoundedSize.width != 0) {
+ bottomRoundedSize =
+ Size(
+ (physicalPixelDisplaySizeRatio * bottomRoundedSize.width + 0.5f).toInt(),
+ (physicalPixelDisplaySizeRatio * bottomRoundedSize.height + 0.5f).toInt()
+ )
+ }
+ }
+ }
+
+ fun dump(pw: PrintWriter) {
+ pw.println("DebugRoundedCornerDelegate state:")
+ pw.println(" hasTop=$hasTop")
+ pw.println(" hasBottom=$hasBottom")
+ pw.println(" topRoundedSize(w,h)=(${topRoundedSize.width},${topRoundedSize.height})")
+ pw.println(
+ " bottomRoundedSize(w,h)=(${bottomRoundedSize.width},${bottomRoundedSize.height})"
+ )
+ pw.println(" physicalPixelDisplaySizeRatio=$physicalPixelDisplaySizeRatio")
+ }
+}
+
+/** Encapsulates the data coming in from the command line args and turns into a [PathDrawable] */
+data class DebugRoundedCornerModel(
+ val path: Path,
+ val width: Int,
+ val height: Int,
+ val scaleX: Float,
+ val scaleY: Float,
+) {
+ fun size() = Size(width, height)
+
+ fun toPathDrawable(paint: Paint) =
+ PathDrawable(
+ path,
+ width,
+ height,
+ scaleX,
+ scaleY,
+ paint,
+ )
+}
+
+/**
+ * PathDrawable accepts paths from the command line via [DebugRoundedCornerModel], and renders them
+ * in the canvas provided by the screen decor rounded corner provider
+ */
+class PathDrawable(
+ val path: Path,
+ val width: Int,
+ val height: Int,
+ val scaleX: Float = 1f,
+ val scaleY: Float = 1f,
+ val paint: Paint,
+) : Drawable() {
+ private var cf: ColorFilter? = null
+
+ override fun draw(canvas: Canvas) {
+ if (scaleX != 1f || scaleY != 1f) {
+ canvas.scale(scaleX, scaleY)
+ }
+ canvas.drawPath(path, paint)
+ }
+
+ override fun getIntrinsicHeight(): Int = height
+ override fun getIntrinsicWidth(): Int = width
+
+ override fun getOpacity(): Int = PixelFormat.OPAQUE
+
+ override fun setAlpha(alpha: Int) {}
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ cf = colorFilter
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
index 8b4aeef..c64766a 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -27,44 +27,50 @@
import com.android.systemui.R
import java.io.PrintWriter
-class RoundedCornerResDelegate(
+interface RoundedCornerResDelegate {
+ val hasTop: Boolean
+ val topRoundedDrawable: Drawable?
+ val topRoundedSize: Size
+
+ val hasBottom: Boolean
+ val bottomRoundedDrawable: Drawable?
+ val bottomRoundedSize: Size
+
+ var physicalPixelDisplaySizeRatio: Float
+
+ fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?)
+}
+
+/**
+ * Delegate for the device-default rounded corners. These will always be loaded from the config
+ * values `R.array.config_roundedCornerTopDrawableArray` and `R.drawable.rounded_corner_top`
+ */
+class RoundedCornerResDelegateImpl(
private val res: Resources,
private var displayUniqueId: String?
-) : Dumpable {
-
- private val density: Float
- get() = res.displayMetrics.density
+) : RoundedCornerResDelegate, Dumpable {
private var reloadToken: Int = 0
- var hasTop: Boolean = false
+ override var hasTop: Boolean = false
private set
- var hasBottom: Boolean = false
+ override var hasBottom: Boolean = false
private set
- var topRoundedDrawable: Drawable? = null
+ override var topRoundedDrawable: Drawable? = null
private set
- var bottomRoundedDrawable: Drawable? = null
+ override var bottomRoundedDrawable: Drawable? = null
private set
- var topRoundedSize = Size(0, 0)
+ override var topRoundedSize = Size(0, 0)
private set
- var bottomRoundedSize = Size(0, 0)
+ override var bottomRoundedSize = Size(0, 0)
private set
- var tuningSizeFactor: Int? = null
- set(value) {
- if (field == value) {
- return
- }
- field = value
- reloadMeasures()
- }
-
- var physicalPixelDisplaySizeRatio: Float = 1f
+ override var physicalPixelDisplaySizeRatio: Float = 1f
set(value) {
if (field == value) {
return
@@ -78,7 +84,7 @@
reloadMeasures()
}
- fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
+ override fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
if (displayUniqueId != newDisplayUniqueId) {
displayUniqueId = newDisplayUniqueId
newReloadToken ?.let { reloadToken = it }
@@ -122,19 +128,6 @@
bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
}
- tuningSizeFactor?.let {
- if (it <= 0) {
- return
- }
- val length: Int = (it * density).toInt()
- if (topRoundedSize.width > 0) {
- topRoundedSize = Size(length, length)
- }
- if (bottomRoundedSize.width > 0) {
- bottomRoundedSize = Size(length, length)
- }
- }
-
if (physicalPixelDisplaySizeRatio != 1f) {
if (topRoundedSize.width != 0) {
topRoundedSize = Size(
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index c503846..0f3345f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -249,10 +249,18 @@
@JvmField
val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer", teamfood = true)
+
+ /** Keyguard Migration */
+
/** Migrate the indication area to the new keyguard root view. */
// TODO(b/280067944): Tracking bug.
@JvmField
- val MIGRATE_INDICATION_AREA = unreleasedFlag(236, "migrate_indication_area")
+ val MIGRATE_INDICATION_AREA = unreleasedFlag(236, "migrate_indication_area", teamfood = true)
+
+ /** Migrate the lock icon view to the new keyguard root view. */
+ // TODO(b/286552209): Tracking bug.
+ @JvmField
+ val MIGRATE_LOCK_ICON = unreleasedFlag(238, "migrate_lock_icon")
/** Whether to listen for fingerprint authentication over keyguard occluding activities. */
// TODO(b/283260512): Tracking bug.
@@ -262,7 +270,11 @@
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
@JvmField
- val KEYGUARD_TALKBACK_FIX = unreleasedFlag(238, "keyguard_talkback_fix")
+ val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
+
+ // TODO(b/287268101): Tracking bug.
+ @JvmField
+ val TRANSIT_CLOCK = unreleasedFlag(239, "lockscreen_custom_transit_clock")
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@@ -478,7 +490,7 @@
@Keep
@JvmField
val WM_CAPTION_ON_SHELL =
- sysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", default = false)
+ sysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", default = true)
@Keep
@JvmField
@@ -731,6 +743,12 @@
val ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD =
releasedFlag(2900, "zj_285570694_lockscreen_transition_from_aod")
+ // 3000 - dream
+ // TODO(b/285059790) : Tracking Bug
+ @JvmField
+ val LOCKSCREEN_WALLPAPER_DREAM_ENABLED =
+ unreleasedFlag(3000, name = "enable_lockscreen_wallpaper_dream")
+
// TODO(b/283084712): Tracking Bug
@JvmField
val IMPROVED_HUN_ANIMATIONS = unreleasedFlag(283084712, "improved_hun_animations")
@@ -740,6 +758,11 @@
val BIGPICTURE_NOTIFICATION_LAZY_LOADING =
unreleasedFlag(283447257, "bigpicture_notification_lazy_loading")
+ // TODO(b/283740863): Tracking Bug
+ @JvmField
+ val ENABLE_NEW_PRIVACY_DIALOG =
+ unreleasedFlag(283740863, "enable_new_privacy_dialog", teamfood = false)
+
// 2900 - CentralSurfaces-related flags
// TODO(b/285174336): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 5248364..040ee79 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -250,6 +250,7 @@
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
+ private int mOrientation;
private final Optional<CentralSurfaces> mCentralSurfacesOptional;
private final ShadeController mShadeController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -394,6 +395,7 @@
mRingerModeTracker = ringerModeTracker;
mMainHandler = handler;
mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
+ mOrientation = resources.getConfiguration().orientation;
mCentralSurfacesOptional = centralSurfacesOptional;
mShadeController = shadeController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -750,8 +752,10 @@
@Override
public void onConfigChanged(Configuration newConfig) {
if (mDialog != null && mDialog.isShowing()
- && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp)) {
+ && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp
+ || newConfig.orientation != mOrientation)) {
mSmallestScreenWidthDp = newConfig.smallestScreenWidthDp;
+ mOrientation = newConfig.orientation;
mDialog.refreshDialog();
}
}
@@ -2312,6 +2316,8 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().setTitle(getContext().getString(
+ com.android.systemui.R.string.accessibility_quick_settings_power_menu));
initializeLayout();
mWindowDimAmount = getWindow().getAttributes().dimAmount;
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index 8c0cfba..aa4c88a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.keyguard;
+import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
+
import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.graphics.Color;
@@ -28,6 +30,7 @@
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -75,6 +78,7 @@
// Executor that will show the next message after a delay
private final DelayableExecutor mExecutor;
+ private final FeatureFlags mFeatureFlags;
@VisibleForTesting
@Nullable ShowNextIndication mShowNextIndicationRunnable;
@@ -91,7 +95,8 @@
KeyguardIndicationTextView view,
@Main DelayableExecutor executor,
StatusBarStateController statusBarStateController,
- KeyguardLogger logger
+ KeyguardLogger logger,
+ FeatureFlags flags
) {
super(view);
mMaxAlpha = view.getAlpha();
@@ -100,12 +105,14 @@
? mView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
mStatusBarStateController = statusBarStateController;
mLogger = logger;
+ mFeatureFlags = flags;
init();
}
@Override
protected void onViewAttached() {
mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mView.setAlwaysAnnounceEnabled(mFeatureFlags.isEnabled(KEYGUARD_TALKBACK_FIX));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 94227bc..e6053fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -80,6 +80,8 @@
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.WeakHashMap;
import javax.inject.Inject;
@@ -187,12 +189,13 @@
final IRemoteAnimationRunner runner, final boolean lockscreenLiveWallpaperEnabled) {
return new IRemoteTransition.Stub() {
+ @GuardedBy("mLeashMap")
private final ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = new ArrayMap<>();
private final CounterRotator mCounterRotator = new CounterRotator();
-
@GuardedBy("mLeashMap")
- private IRemoteTransitionFinishedCallback mFinishCallback = null;
+ private final Map<IBinder, IRemoteTransitionFinishedCallback> mFinishCallbacks =
+ new WeakHashMap<>();
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
@@ -200,40 +203,38 @@
throws RemoteException {
Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
+ final RemoteAnimationTarget[] apps;
+ final RemoteAnimationTarget[] wallpapers;
+ final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
synchronized (mLeashMap) {
- final RemoteAnimationTarget[] apps =
- wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
- final RemoteAnimationTarget[] wallpapers =
- wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
- final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
-
- // Set alpha back to 1 for the independent changes because we will be animating
- // children instead.
- for (TransitionInfo.Change chg : info.getChanges()) {
- if (TransitionInfo.isIndependent(chg, info)) {
- t.setAlpha(chg.getLeash(), 1.f);
- }
- }
- initAlphaForAnimationTargets(t, apps);
- if (lockscreenLiveWallpaperEnabled) {
- initAlphaForAnimationTargets(t, wallpapers);
- }
- t.apply();
- mFinishCallback = finishCallback;
- runner.onAnimationStart(
- getTransitionOldType(info.getType(), info.getFlags(), apps),
- apps, wallpapers, nonApps,
- new IRemoteAnimationFinishedCallback.Stub() {
- @Override
- public void onAnimationFinished() throws RemoteException {
- synchronized (mLeashMap) {
- Slog.d(TAG, "Finish IRemoteAnimationRunner.");
- finish();
- }
- }
- }
- );
+ apps = wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
+ wallpapers = wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
+ mFinishCallbacks.put(transition, finishCallback);
}
+
+ // Set alpha back to 1 for the independent changes because we will be animating
+ // children instead.
+ for (TransitionInfo.Change chg : info.getChanges()) {
+ if (TransitionInfo.isIndependent(chg, info)) {
+ t.setAlpha(chg.getLeash(), 1.f);
+ }
+ }
+ initAlphaForAnimationTargets(t, apps);
+ if (lockscreenLiveWallpaperEnabled) {
+ initAlphaForAnimationTargets(t, wallpapers);
+ }
+ t.apply();
+
+ runner.onAnimationStart(
+ getTransitionOldType(info.getType(), info.getFlags(), apps),
+ apps, wallpapers, nonApps,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+ finish(transition);
+ }
+ });
}
public void mergeAnimation(IBinder candidateTransition, TransitionInfo candidateInfo,
@@ -247,10 +248,8 @@
}
try {
- synchronized (mLeashMap) {
- runner.onAnimationCancelled();
- finish();
- }
+ runner.onAnimationCancelled();
+ finish(currentTransition);
} catch (RemoteException e) {
// nothing, we'll just let it finish on its own I guess.
}
@@ -264,18 +263,21 @@
}
}
- @GuardedBy("mLeashMap")
- private void finish() throws RemoteException {
+ private void finish(IBinder transition) throws RemoteException {
+ IRemoteTransitionFinishedCallback finishCallback = null;
SurfaceControl.Transaction finishTransaction = null;
- if (mCounterRotator.getSurface() != null
- && mCounterRotator.getSurface().isValid()) {
- finishTransaction = new SurfaceControl.Transaction();
- mCounterRotator.cleanUp(finishTransaction);
+
+ synchronized (mLeashMap) {
+ if (mCounterRotator.getSurface() != null
+ && mCounterRotator.getSurface().isValid()) {
+ finishTransaction = new SurfaceControl.Transaction();
+ mCounterRotator.cleanUp(finishTransaction);
+ }
+ mLeashMap.clear();
+ finishCallback = mFinishCallbacks.remove(transition);
}
- mLeashMap.clear();
- final IRemoteTransitionFinishedCallback finishCallback = mFinishCallback;
+
if (finishCallback != null) {
- mFinishCallback = null;
finishCallback.onTransitionFinished(null /* wct */, finishTransaction);
} else if (finishTransaction != null) {
finishTransaction.apply();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 05c23ae..e8881a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -47,9 +47,10 @@
private var indicationAreaHandle: DisposableHandle? = null
override fun start() {
- bindIndicationArea(
+ val notificationPanel =
notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup
- )
+ bindIndicationArea(notificationPanel)
+ bindLockIconView(notificationPanel)
}
fun bindIndicationArea(legacyParent: ViewGroup) {
@@ -74,4 +75,16 @@
indicationController
)
}
+
+ private fun bindLockIconView(legacyParent: ViewGroup) {
+ if (featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) {
+ legacyParent.requireViewById<View>(R.id.lock_icon_view).let {
+ legacyParent.removeView(it)
+ }
+ } else {
+ keyguardRootView.findViewById<View?>(R.id.lock_icon_view)?.let {
+ keyguardRootView.removeView(it)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 049aa0d..ce8ab23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -35,6 +35,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -137,6 +138,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
@@ -170,6 +172,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -283,6 +286,8 @@
* keyguard to show even if it is disabled for the current user.
*/
public static final String OPTION_FORCE_SHOW = "force_show";
+ public static final String SYS_BOOT_REASON_PROP = "sys.boot.reason.last";
+ public static final String REBOOT_MAINLINE_UPDATE = "reboot,mainline_update";
private final DreamOverlayStateController mDreamOverlayStateController;
/** The stream type that the lock sounds are tied to. */
@@ -321,6 +326,7 @@
private final SecureSettings mSecureSettings;
private final SystemSettings mSystemSettings;
private final SystemClock mSystemClock;
+ private SystemPropertiesHelper mSystemPropertiesHelper;
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -852,9 +858,16 @@
strongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(currentUser);
if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
- return KeyguardSecurityView.PROMPT_REASON_RESTART;
+ String reasonForReboot = mSystemPropertiesHelper.get(SYS_BOOT_REASON_PROP);
+ if (Objects.equals(reasonForReboot, REBOOT_MAINLINE_UPDATE)) {
+ return KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE;
+ } else {
+ return KeyguardSecurityView.PROMPT_REASON_RESTART;
+ }
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+ } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0) {
+ return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
} else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
} else if (trustAgentsEnabled
@@ -1247,7 +1260,8 @@
@Override
public void onPrimaryBouncerShowingChanged() {
synchronized (KeyguardViewMediator.this) {
- if (mKeyguardStateController.isPrimaryBouncerShowing()) {
+ if (mKeyguardStateController.isPrimaryBouncerShowing()
+ && !mKeyguardStateController.isKeyguardGoingAway()) {
mPendingPinLock = false;
}
adjustStatusBarLocked(mKeyguardStateController.isPrimaryBouncerShowing(), false);
@@ -1313,7 +1327,8 @@
SystemSettings systemSettings,
SystemClock systemClock,
@Main CoroutineDispatcher mainDispatcher,
- Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
+ SystemPropertiesHelper systemPropertiesHelper) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1330,6 +1345,7 @@
mSecureSettings = secureSettings;
mSystemSettings = systemSettings;
mSystemClock = systemClock;
+ mSystemPropertiesHelper = systemPropertiesHelper;
mStatusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mKeyguardDisplayManager = keyguardDisplayManager;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt
index a44df7e..d8eb81c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.keyguard.dagger
+import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.NoopDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.NoopKeyguardFaceAuthInteractor
import dagger.Binds
@@ -32,4 +34,9 @@
interface KeyguardFaceAuthNotSupportedModule {
@Binds
fun keyguardFaceAuthInteractor(impl: NoopKeyguardFaceAuthInteractor): KeyguardFaceAuthInteractor
+
+ @Binds
+ fun deviceEntryFaceAuthRepository(
+ impl: NoopDeviceEntryFaceAuthRepository
+ ): DeviceEntryFaceAuthRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 5622df1..ced41aa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -43,6 +43,7 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -142,7 +143,8 @@
SystemSettings systemSettings,
SystemClock systemClock,
@Main CoroutineDispatcher mainDispatcher,
- Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
+ SystemPropertiesHelper systemPropertiesHelper) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -182,7 +184,8 @@
systemSettings,
systemClock,
mainDispatcher,
- dreamingToLockscreenTransitionViewModel);
+ dreamingToLockscreenTransitionViewModel,
+ systemPropertiesHelper);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index f9e9a93..128057a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -335,6 +335,11 @@
biometricSettingsRepository.isCurrentUserInLockdown.isFalse(),
"userHasNotLockedDownDevice",
tableLogBuffer
+ ),
+ logAndObserve(
+ keyguardRepository.isKeyguardShowing,
+ "isKeyguardShowing",
+ tableLogBuffer
)
)
.reduce(::and)
@@ -598,7 +603,7 @@
const val DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000L
/** Number of allowed retries whenever there is a face hardware error */
- const val HAL_ERROR_RETRY_MAX = 20
+ const val HAL_ERROR_RETRY_MAX = 5
/** Timeout before retries whenever there is a HAL error. */
const val HAL_ERROR_RETRY_TIMEOUT = 500L // ms
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
new file mode 100644
index 0000000..abe59b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.keyguard.data.repository
+
+import com.android.keyguard.FaceAuthUiEvent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.AuthenticationStatus
+import com.android.systemui.keyguard.shared.model.DetectionStatus
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.emptyFlow
+
+/**
+ * Implementation of the repository that noops all face auth operations.
+ *
+ * This is required for SystemUI variants that do not support face authentication but still inject
+ * other SysUI components that depend on [DeviceEntryFaceAuthRepository].
+ */
+@SysUISingleton
+class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceAuthRepository {
+ override val isAuthenticated: Flow<Boolean>
+ get() = emptyFlow()
+
+ private val _canRunFaceAuth = MutableStateFlow(false)
+ override val canRunFaceAuth: StateFlow<Boolean> = _canRunFaceAuth
+
+ override val authenticationStatus: Flow<AuthenticationStatus>
+ get() = emptyFlow()
+
+ override val detectionStatus: Flow<DetectionStatus>
+ get() = emptyFlow()
+
+ private val _isLockedOut = MutableStateFlow(false)
+ override val isLockedOut: StateFlow<Boolean> = _isLockedOut
+
+ private val _isAuthRunning = MutableStateFlow(false)
+ override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
+
+ override val isBypassEnabled: Flow<Boolean>
+ get() = emptyFlow()
+
+ /**
+ * Trigger face authentication.
+ *
+ * [uiEvent] provided should be logged whenever face authentication runs. Invocation should be
+ * ignored if face authentication is already running. Results should be propagated through
+ * [authenticationStatus]
+ *
+ * Run only face detection when [fallbackToDetection] is true and [canRunFaceAuth] is false.
+ */
+ override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {}
+
+ /** Stop currently running face authentication or detection. */
+ override fun cancel() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 1c2e85b..b92d104 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -346,6 +346,10 @@
?.largeClock
?.events
?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
+ clockController.clock
+ ?.smallClock
+ ?.events
+ ?.onTargetRegionChanged(KeyguardClockSwitch.getSmallClockRegion(parentView))
}
}
parentView.addOnLayoutChangeListener(layoutChangeListener)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
index abf0e80..a62f383 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
@@ -23,6 +23,7 @@
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
+import com.android.keyguard.LockIconView
import com.android.systemui.R
/** Provides a container for all keyguard ui content. */
@@ -37,6 +38,7 @@
init {
addIndicationTextArea()
+ addLockIconView()
}
private fun addIndicationTextArea() {
@@ -54,6 +56,17 @@
)
}
+ private fun addLockIconView() {
+ val view = LockIconView(context, attrs).apply { id = R.id.lock_icon_view }
+ addView(
+ view,
+ LayoutParams(
+ WRAP_CONTENT,
+ WRAP_CONTENT,
+ )
+ )
+ }
+
private fun Int.dp(): Int {
return context.resources.getDimensionPixelSize(this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index f727784..27301e9 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -21,9 +21,9 @@
import android.graphics.RectF
import androidx.core.graphics.toRectF
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.ScreenDecorationsLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
@@ -164,4 +164,49 @@
fun cameraProtectionEvent(@CompileTimeConstant cameraProtectionEvent: String) {
logBuffer.log(TAG, DEBUG, cameraProtectionEvent)
}
+
+ fun logRotationChangeDeferred(currentRot: Int, newRot: Int) {
+ logBuffer.log(
+ TAG,
+ INFO,
+ {
+ int1 = currentRot
+ int2 = newRot
+ },
+ { "Rotation changed, deferring $int2, staying at $int2" },
+ )
+ }
+
+ fun logRotationChanged(oldRot: Int, newRot: Int) {
+ logBuffer.log(
+ TAG,
+ INFO,
+ {
+ int1 = oldRot
+ int2 = newRot
+ },
+ { "Rotation changed from $int1 to $int2" }
+ )
+ }
+
+ fun logDisplayModeChanged(currentMode: Int, newMode: Int) {
+ logBuffer.log(
+ TAG,
+ INFO,
+ {
+ int1 = currentMode
+ int2 = newMode
+ },
+ { "Resolution changed, deferring mode change to $int2, staying at $int1" },
+ )
+ }
+
+ fun logUserSwitched(newUser: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = newUser },
+ { "UserSwitched newUserId=$int1. Updating color inversion setting" },
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DisableFlagsRepositoryLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/DisableFlagsRepositoryLog.kt
new file mode 100644
index 0000000..e141291
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DisableFlagsRepositoryLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.log.dagger
+
+import com.android.systemui.log.LogBuffer
+import javax.inject.Qualifier
+
+/** A [LogBuffer] for changes to [DisableFlagsRepository]. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class DisableFlagsRepositoryLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 0261ee5..3497285 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -224,6 +224,15 @@
false /* systrace */);
}
+ /** Provides a logging buffer for the disable flags repository. */
+ @Provides
+ @SysUISingleton
+ @DisableFlagsRepositoryLog
+ public static LogBuffer provideDisableFlagsRepositoryLogBuffer(LogBufferFactory factory) {
+ return factory.create("DisableFlagsRepository", 40 /* maxSize */,
+ false /* systrace */);
+ }
+
/** Provides a logging buffer for logs related to swipe up gestures. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 1e9a466..70b5e75 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -21,6 +21,8 @@
import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Configuration
+import android.database.ContentObserver
+import android.provider.Settings
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
import android.util.MathUtils
@@ -64,6 +66,7 @@
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.animation.requiresRemeasuring
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.traceSection
import java.io.PrintWriter
@@ -105,6 +108,7 @@
private val mediaFlags: MediaFlags,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val globalSettings: GlobalSettings,
) : Dumpable {
/** The current width of the carousel */
var currentCarouselWidth: Int = 0
@@ -169,6 +173,13 @@
private var carouselLocale: Locale? = null
+ private val animationScaleObserver: ContentObserver =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ MediaPlayerData.players().forEach { it.updateAnimatorDurationScale() }
+ }
+ }
+
/** Whether the media card currently has the "expanded" layout */
@VisibleForTesting
var currentlyExpanded = true
@@ -529,6 +540,12 @@
listenForAnyStateToGoneKeyguardTransition(this)
}
}
+
+ // Notifies all active players about animation scale changes.
+ globalSettings.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+ animationScaleObserver
+ )
}
private fun inflateSettingsButton() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 0819d0d..35082fd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -34,7 +34,6 @@
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Color;
@@ -252,13 +251,6 @@
private boolean mWasPlaying = false;
private boolean mButtonClicked = false;
- private ContentObserver mAnimationScaleObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- updateAnimatorDurationScale();
- }
- };
-
/**
* Initialize a new control panel
*
@@ -318,10 +310,6 @@
mFeatureFlags = featureFlags;
mGlobalSettings = globalSettings;
- mGlobalSettings.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
- mAnimationScaleObserver
- );
updateAnimatorDurationScale();
}
@@ -405,7 +393,10 @@
updateSeekBarVisibility();
}
- private void updateAnimatorDurationScale() {
+ /**
+ * Reloads animator duration scale.
+ */
+ void updateAnimatorDurationScale() {
if (mSeekBarObserver != null) {
mSeekBarObserver.setAnimationEnabled(
mGlobalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f) > 0f);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 0a5b4b3..7712690 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -105,6 +105,7 @@
private WallpaperColors mWallpaperColors;
private boolean mShouldLaunchLeBroadcastDialog;
private boolean mIsLeBroadcastCallbackRegistered;
+ private boolean mDismissing;
MediaOutputBaseAdapter mAdapter;
@@ -265,13 +266,22 @@
mDevicesRecyclerView.setHasFixedSize(false);
// Init bottom buttons
mDoneButton.setOnClickListener(v -> dismiss());
- mStopButton.setOnClickListener(v -> {
- mMediaOutputController.releaseSession();
- dismiss();
- });
+ mStopButton.setOnClickListener(v -> onStopButtonClick());
mAppButton.setOnClickListener(mMediaOutputController::tryToLaunchMediaApplication);
mMediaMetadataSectionLayout.setOnClickListener(
mMediaOutputController::tryToLaunchMediaApplication);
+
+ mDismissing = false;
+ }
+
+ @Override
+ public void dismiss() {
+ // TODO(287191450): remove this once expensive binder calls are removed from refresh().
+ // Due to these binder calls on the UI thread, calling refresh() during dismissal causes
+ // significant frame drops for the dismissal animation. Since the dialog is going away
+ // anyway, we use this state to turn refresh() into a no-op.
+ mDismissing = true;
+ super.dismiss();
}
@Override
@@ -299,7 +309,9 @@
}
void refresh(boolean deviceSetChanged) {
- if (mMediaOutputController.isRefreshing()) {
+ // TODO(287191450): remove binder calls in this method from the UI thread.
+ // If the dialog is going away or is already refreshing, do nothing.
+ if (mDismissing || mMediaOutputController.isRefreshing()) {
return;
}
mMediaOutputController.setRefreshing(true);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 19b32e9..f3865f5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
@@ -36,11 +37,14 @@
*/
@SysUISingleton
public class MediaOutputDialog extends MediaOutputBaseDialog {
- final UiEventLogger mUiEventLogger;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
+ private final UiEventLogger mUiEventLogger;
MediaOutputDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController, UiEventLogger uiEventLogger) {
+ MediaOutputController mediaOutputController, DialogLaunchAnimator dialogLaunchAnimator,
+ UiEventLogger uiEventLogger) {
super(context, broadcastSender, mediaOutputController);
+ mDialogLaunchAnimator = dialogLaunchAnimator;
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController);
if (!aboveStatusbar) {
@@ -138,6 +142,7 @@
}
} else {
mMediaOutputController.releaseSession();
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
dismiss();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 8024886..4c168ec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -28,11 +28,11 @@
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.media.nearby.NearbyMediaDevicesManager
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import java.util.Optional
import javax.inject.Inject
@@ -71,7 +71,8 @@
dialogLaunchAnimator, nearbyMediaDevicesManagerOptional, audioManager,
powerExemptionManager, keyGuardManager, featureFlags, userTracker)
val dialog =
- MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller, uiEventLogger)
+ MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller,
+ dialogLaunchAnimator, uiEventLogger)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 8225c47..99c591f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -462,7 +462,7 @@
* @return Whether the IME is shown on top of the screen given the {@code vis} flag of
* {@link InputMethodService} and the keyguard states.
*/
- public boolean isImeShown(int vis) {
+ public boolean isImeShown(@InputMethodService.ImeWindowVisibility int vis) {
View shadeWindowView = mNotificationShadeWindowController.getWindowRootView();
boolean isKeyguardShowing = mKeyguardStateController.isShowing();
boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 682335e..5bae1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -66,6 +66,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.inputmethodservice.InputMethodService;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -1047,8 +1048,9 @@
// ----- CommandQueue Callbacks -----
@Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index b96ca7a..cecf043 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -224,7 +224,6 @@
return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
}
});
- controller.overrideIconTintForNavMode(true);
return controller;
}
@@ -339,8 +338,9 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition, boolean showImeSwitcher) {
boolean imeShown = mNavBarHelper.isImeShown(vis);
if (!imeShown) {
// Count imperceptible changes as visible so we transition taskbar out quickly.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index cf192f9..7b86d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -264,6 +264,7 @@
private boolean mGestureBlockingActivityRunning;
private boolean mIsNewBackAffordanceEnabled;
private boolean mIsTrackpadGestureFeaturesEnabled;
+ private boolean mIsTrackpadThreeFingerSwipe;
private boolean mIsButtonForcedVisible;
private InputMonitor mInputMonitor;
@@ -986,18 +987,21 @@
(int) mEndPoint.x, (int) mEndPoint.y,
mEdgeWidthLeft + mLeftInset,
mDisplaySize.x - (mEdgeWidthRight + mRightInset),
- mUseMLModel ? mMLResults : -2, logPackageName);
+ mUseMLModel ? mMLResults : -2, logPackageName,
+ mIsTrackpadThreeFingerSwipe ? SysUiStatsLog.BACK_GESTURE__INPUT_TYPE__TRACKPAD
+ : SysUiStatsLog.BACK_GESTURE__INPUT_TYPE__TOUCH);
}
private void onMotionEvent(MotionEvent ev) {
int action = ev.getActionMasked();
- boolean isTrackpadThreeFingerSwipe = isTrackpadThreeFingerSwipe(
- mIsTrackpadGestureFeaturesEnabled, ev);
if (action == MotionEvent.ACTION_DOWN) {
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Start gesture: " + ev);
}
+ mIsTrackpadThreeFingerSwipe = isTrackpadThreeFingerSwipe(
+ mIsTrackpadGestureFeaturesEnabled, ev);
+
// ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
// ACTION_DOWN, in that case we should just reuse the old instance.
mVelocityTracker.clear();
@@ -1005,7 +1009,7 @@
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mInputEventReceiver.setBatchingEnabled(false);
- if (isTrackpadThreeFingerSwipe) {
+ if (mIsTrackpadThreeFingerSwipe) {
// Since trackpad gestures don't have zones, this will be determined later by the
// direction of the gesture. {@code mIsOnLeftEdge} is set to false to begin with.
mDeferSetIsOnLeftEdge = true;
@@ -1021,11 +1025,11 @@
&& !mGestureBlockingActivityRunning
&& !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
&& !isTrackpadScroll(mIsTrackpadGestureFeaturesEnabled, ev);
- if (isTrackpadThreeFingerSwipe) {
+ if (mIsTrackpadThreeFingerSwipe) {
// Trackpad back gestures don't have zones, so we don't need to check if the down
// event is within insets.
mAllowGesture = isBackAllowedCommon && isValidTrackpadBackGesture(
- isTrackpadThreeFingerSwipe);
+ true /* isTrackpadEvent */);
} else {
mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
&& isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
@@ -1036,7 +1040,7 @@
mEdgeBackPlugin.onMotionEvent(ev);
dispatchToBackAnimation(ev);
}
- if (mLogGesture || isTrackpadThreeFingerSwipe) {
+ if (mLogGesture || mIsTrackpadThreeFingerSwipe) {
mDownPoint.set(ev.getX(), ev.getY());
mEndPoint.set(-1, -1);
mThresholdCrossed = false;
@@ -1050,7 +1054,7 @@
"Gesture [%d [%s],alw=%B, t3fs=%B, left=%B, defLeft=%B, backAlw=%B, disbld=%B,"
+ " qsDisbld=%b, blkdAct=%B, pip=%B,"
+ " disp=%s, wl=%d, il=%d, wr=%d, ir=%d, excl=%s]",
- curTime, curTimeStr, mAllowGesture, isTrackpadThreeFingerSwipe,
+ curTime, curTimeStr, mAllowGesture, mIsTrackpadThreeFingerSwipe,
mIsOnLeftEdge, mDeferSetIsOnLeftEdge, mIsBackGestureAllowed,
QuickStepContract.isBackGestureDisabled(mSysUiFlags), mDisabledForQuickstep,
mGestureBlockingActivityRunning, mIsInPip, mDisplaySize,
@@ -1059,7 +1063,7 @@
if (!mThresholdCrossed) {
mEndPoint.x = (int) ev.getX();
mEndPoint.y = (int) ev.getY();
- if (action == MotionEvent.ACTION_POINTER_DOWN && !isTrackpadThreeFingerSwipe) {
+ if (action == MotionEvent.ACTION_POINTER_DOWN && !mIsTrackpadThreeFingerSwipe) {
if (mAllowGesture) {
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
if (DEBUG_MISSING_GESTURE) {
@@ -1071,7 +1075,7 @@
mLogGesture = false;
return;
} else if (action == MotionEvent.ACTION_MOVE) {
- if (isTrackpadThreeFingerSwipe && mDeferSetIsOnLeftEdge) {
+ if (mIsTrackpadThreeFingerSwipe && mDeferSetIsOnLeftEdge) {
// mIsOnLeftEdge is determined by the relative position between the down
// and the current motion event for trackpad gestures instead of zoning.
mIsOnLeftEdge = mEndPoint.x > mDownPoint.x;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
index cd52ec2..ac6aabb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -34,7 +34,6 @@
},
{
disableFlagsLogger.getDisableFlagsString(
- old = null,
new = DisableFlagsLogger.DisableState(int1, int2),
newAfterLocalModification =
DisableFlagsLogger.DisableState(long1.toInt(), long2.toInt())
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 1712490..d511d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -114,11 +114,18 @@
mQs = qs;
}
+ private void reloadAdapterTileHeight(@Nullable RecyclerView.Adapter adapter) {
+ if (adapter instanceof TileAdapter) {
+ ((TileAdapter) adapter).reloadTileHeight();
+ }
+ }
+
/** Animate and show QSCustomizer panel.
* @param x,y Location on screen of {@code edit} button to determine center of animation.
*/
void show(int x, int y, TileAdapter tileAdapter) {
if (!isShown) {
+ reloadAdapterTileHeight(tileAdapter);
mRecyclerView.getLayoutManager().scrollToPosition(0);
int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
@@ -136,6 +143,7 @@
void showImmediately() {
if (!isShown) {
+ reloadAdapterTileHeight(mRecyclerView.getAdapter());
mRecyclerView.getLayoutManager().scrollToPosition(0);
setVisibility(VISIBLE);
mClipper.cancelAnimator();
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 6a05684..596475e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -43,9 +43,11 @@
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.TileLayout;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
@@ -114,6 +116,9 @@
private RecyclerView mRecyclerView;
private int mNumColumns;
+ private TextView mTempTextView;
+ private int mMinTileViewHeight;
+
@Inject
public TileAdapter(
@QSThemedContext Context context,
@@ -129,6 +134,8 @@
mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
mAccessibilityDelegate = new TileAdapterDelegate();
mSizeLookup.setSpanIndexCacheEnabled(true);
+ mTempTextView = new TextView(context);
+ mMinTileViewHeight = context.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
}
@Override
@@ -318,6 +325,10 @@
@Override
public void onBindViewHolder(final Holder holder, int position) {
+ if (holder.mTileView != null) {
+ holder.mTileView.setMinimumHeight(mMinTileViewHeight);
+ }
+
if (holder.getItemViewType() == TYPE_HEADER) {
setSelectableForHeaders(holder.itemView);
return;
@@ -860,4 +871,19 @@
- buttonMinWidth
- res.getDimensionPixelSize(R.dimen.qs_tile_margin_top_bottom);
}
+
+ /**
+ * Re-estimate the tile view height based under current font scaling. Like
+ * {@link TileLayout#estimateCellHeight()}, the tile view height would be estimated with 2
+ * labels as general case.
+ */
+ public void reloadTileHeight() {
+ final int minHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+ FontSizeUtils.updateFontSize(mTempTextView, R.dimen.qs_tile_text_size);
+ int unspecifiedSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ mTempTextView.measure(unspecifiedSpec, unspecifiedSpec);
+ int padding = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding);
+ int estimatedTileViewHeight = mTempTextView.getMeasuredHeight() * 2 + padding * 2;
+ mMinTileViewHeight = Math.max(minHeight, estimatedTileViewHeight);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index cd69f4e..e541681 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -130,6 +130,11 @@
d.setLayoutDirection(getLayoutDirection());
}
+ final Drawable lastDrawable = iv.getDrawable();
+ if (lastDrawable instanceof Animatable2) {
+ ((Animatable2) lastDrawable).clearAnimationCallbacks();
+ }
+
if (iv instanceof SlashImageView) {
((SlashImageView) iv).setAnimationEnabled(shouldAnimate);
((SlashImageView) iv).setState(null, d);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index c013486..423fa80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -38,7 +38,9 @@
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SystemSettings
@@ -57,11 +59,13 @@
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
qsLogger: QSLogger,
+ private val keyguardStateController: KeyguardStateController,
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
private val systemClock: SystemClock,
private val featureFlags: FeatureFlags,
+ private val userTracker: UserTracker,
@Background private val backgroundDelayableExecutor: DelayableExecutor
) :
QSTileImpl<QSTile.State?>(
@@ -86,26 +90,40 @@
}
override fun handleClick(view: View?) {
- mUiHandler.post {
+ // We animate from the touched view only if we are not on the keyguard
+ val animateFromView: Boolean = view != null && !keyguardStateController.isShowing
+
+ val runnable = Runnable {
val dialog: SystemUIDialog =
FontScalingDialog(
mContext,
systemSettings,
secureSettings,
systemClock,
+ userTracker,
mainHandler,
backgroundDelayableExecutor
)
- if (view != null) {
+ if (animateFromView) {
dialogLaunchAnimator.showFromView(
dialog,
- view,
+ view!!,
DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
)
} else {
dialog.show()
}
}
+
+ mainHandler.post {
+ mActivityStarter.executeRunnableDismissingKeyguard(
+ runnable,
+ /* cancelAction= */ null,
+ /* dismissShade= */ true,
+ /* afterKeyguardGone= */ true,
+ /* deferred= */ false
+ )
+ }
}
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index abeb5af..ec12580 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -172,7 +172,9 @@
private Executor mExecutor;
private AccessPointController mAccessPointController;
private IntentFilter mConnectionStateFilter;
- private InternetDialogCallback mCallback;
+ @VisibleForTesting
+ @Nullable
+ InternetDialogCallback mCallback;
private UiEventLogger mUiEventLogger;
private BroadcastDispatcher mBroadcastDispatcher;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -215,12 +217,16 @@
new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshCarrierInfo() {
- mCallback.onRefreshCarrierInfo();
+ if (mCallback != null) {
+ mCallback.onRefreshCarrierInfo();
+ }
}
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
- mCallback.onSimStateChanged();
+ if (mCallback != null) {
+ mCallback.onSimStateChanged();
+ }
}
};
@@ -331,6 +337,7 @@
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
mConnectivityManager.unregisterNetworkCallback(mConnectivityManagerNetworkCallback);
mConnectedWifiInternetMonitor.unregisterCallback();
+ mCallback = null;
}
@VisibleForTesting
@@ -724,7 +731,7 @@
ActivityLaunchAnimator.Controller controller =
mDialogLaunchAnimator.createActivityLaunchController(view);
- if (controller == null) {
+ if (controller == null && mCallback != null) {
mCallback.dismissDialog();
}
@@ -1095,7 +1102,9 @@
mHasWifiEntries = false;
}
- mCallback.onAccessPointsChanged(wifiEntries, connectedEntry, hasMoreWifiEntries);
+ if (mCallback != null) {
+ mCallback.onAccessPointsChanged(wifiEntries, connectedEntry, hasMoreWifiEntries);
+ }
}
@Override
@@ -1117,34 +1126,46 @@
@Override
public void onServiceStateChanged(@NonNull ServiceState serviceState) {
- mCallback.onServiceStateChanged(serviceState);
+ if (mCallback != null) {
+ mCallback.onServiceStateChanged(serviceState);
+ }
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
- mCallback.onDataConnectionStateChanged(state, networkType);
+ if (mCallback != null) {
+ mCallback.onDataConnectionStateChanged(state, networkType);
+ }
}
@Override
public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) {
- mCallback.onSignalStrengthsChanged(signalStrength);
+ if (mCallback != null) {
+ mCallback.onSignalStrengthsChanged(signalStrength);
+ }
}
@Override
public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
mSubIdTelephonyDisplayInfoMap.put(mSubId, telephonyDisplayInfo);
- mCallback.onDisplayInfoChanged(telephonyDisplayInfo);
+ if (mCallback != null) {
+ mCallback.onDisplayInfoChanged(telephonyDisplayInfo);
+ }
}
@Override
public void onUserMobileDataStateChanged(boolean enabled) {
- mCallback.onUserMobileDataStateChanged(enabled);
+ if (mCallback != null) {
+ mCallback.onUserMobileDataStateChanged(enabled);
+ }
}
@Override
public void onCarrierNetworkChange(boolean active) {
mCarrierNetworkChangeMode = active;
- mCallback.onCarrierNetworkChange(active);
+ if (mCallback != null) {
+ mCallback.onCarrierNetworkChange(active);
+ }
}
}
@@ -1171,14 +1192,18 @@
scanWifiAccessPoints();
}
// update UI
- mCallback.onCapabilitiesChanged(network, capabilities);
+ if (mCallback != null) {
+ mCallback.onCapabilitiesChanged(network, capabilities);
+ }
}
@Override
@WorkerThread
public void onLost(@NonNull Network network) {
mHasEthernet = false;
- mCallback.onLost(network);
+ if (mCallback != null) {
+ mCallback.onLost(network);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 752471d..0a9839e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -16,7 +16,7 @@
package com.android.systemui.scene
-import com.android.systemui.scene.data.model.SceneContainerConfigModule
+import com.android.systemui.scene.shared.model.SceneContainerConfigModule
import com.android.systemui.scene.ui.composable.SceneModule
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModelModule
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 61b162b..1ebeced 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -16,7 +16,7 @@
package com.android.systemui.scene.data.repository
-import com.android.systemui.scene.data.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import javax.inject.Inject
@@ -28,11 +28,9 @@
class SceneContainerRepository
@Inject
constructor(
- containerConfigurations: Set<SceneContainerConfig>,
+ private val containerConfigByName: Map<String, SceneContainerConfig>,
) {
- private val containerConfigByName: Map<String, SceneContainerConfig> =
- containerConfigurations.associateBy { config -> config.name }
private val containerVisibilityByName: Map<String, MutableStateFlow<Boolean>> =
containerConfigByName
.map { (containerName, _) -> containerName to MutableStateFlow(true) }
@@ -48,21 +46,6 @@
.map { (containerName, _) -> containerName to MutableStateFlow(1f) }
.toMap()
- init {
- val repeatedContainerNames =
- containerConfigurations
- .groupingBy { config -> config.name }
- .eachCount()
- .filter { (_, count) -> count > 1 }
- check(repeatedContainerNames.isEmpty()) {
- "Container names must be unique. The following container names appear more than once: ${
- repeatedContainerNames
- .map { (name, count) -> "\"$name\" appears $count times" }
- .joinToString(", ")
- }"
- }
- }
-
/**
* Returns the keys to all scenes in the container with the given name.
*
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfig.kt
rename to packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
index d0769eb..0327edb 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 The Android Open 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,9 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.scene.data.model
-
-import com.android.systemui.scene.shared.model.SceneKey
+package com.android.systemui.scene.shared.model
/** Models the configuration of a single scene container. */
data class SceneContainerConfig(
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfigModule.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfigModule.kt
rename to packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
index 0af8094..7562a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneContainerConfigModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 The Android Open 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,11 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.scene.data.model
+package com.android.systemui.scene.shared.model
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.scene.shared.model.SceneContainerNames
-import com.android.systemui.scene.shared.model.SceneKey
import dagger.Module
import dagger.Provides
import javax.inject.Named
diff --git a/packages/SystemUI/src/com/android/systemui/scene/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/startable/SceneContainerStartable.kt
new file mode 100644
index 0000000..a29e92a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/startable/SceneContainerStartable.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.scene.startable
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneContainerNames
+import com.android.systemui.scene.ui.view.SceneWindowRootView
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+import javax.inject.Named
+
+@SysUISingleton
+class SceneContainerStartable
+@Inject
+constructor(
+ private val view: WindowRootView,
+ @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) private val viewModel: SceneContainerViewModel,
+ @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) private val containerConfig: SceneContainerConfig,
+ @Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
+ private val scenes: Set<@JvmSuppressWildcards Scene>,
+) : CoreStartable {
+
+ override fun start() {
+ (view as? SceneWindowRootView)?.init(
+ viewModel = viewModel,
+ containerConfig = containerConfig,
+ scenes = scenes,
+ )
+ }
+}
+
+@Module
+interface SceneContainerStartableModule {
+ @Binds
+ @IntoMap
+ @ClassKey(SceneContainerStartable::class)
+ fun bind(impl: SceneContainerStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 8f001ec..2ad5429 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -2,6 +2,73 @@
import android.content.Context
import android.util.AttributeSet
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import kotlinx.coroutines.launch
/** A root view of the main SysUI window that supports scenes. */
-class SceneWindowRootView(context: Context?, attrs: AttributeSet?) : WindowRootView(context, attrs)
\ No newline at end of file
+class SceneWindowRootView(
+ context: Context,
+ attrs: AttributeSet?,
+) :
+ WindowRootView(
+ context,
+ attrs,
+ ) {
+ fun init(
+ viewModel: SceneContainerViewModel,
+ containerConfig: SceneContainerConfig,
+ scenes: Set<Scene>,
+ ) {
+ val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
+ val sortedSceneByKey: Map<SceneKey, Scene> = buildMap {
+ containerConfig.sceneKeys.forEach { sceneKey ->
+ val scene =
+ checkNotNull(unsortedSceneByKey[sceneKey]) {
+ "Scene not found for key \"$sceneKey\"!"
+ }
+
+ put(sceneKey, scene)
+ }
+ }
+
+ repeatWhenAttached {
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ setViewTreeOnBackPressedDispatcherOwner(
+ object : OnBackPressedDispatcherOwner {
+ override val onBackPressedDispatcher =
+ OnBackPressedDispatcher().apply {
+ setOnBackInvokedDispatcher(viewRootImpl.onBackInvokedDispatcher)
+ }
+
+ override val lifecycle: Lifecycle =
+ this@repeatWhenAttached.lifecycle
+ }
+ )
+
+ addView(
+ ComposeFacade.createSceneContainerView(
+ context = context,
+ viewModel = viewModel,
+ sceneByKey = sortedSceneByKey,
+ )
+ )
+ }
+
+ // Here when destroyed.
+ removeAllViews()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
index a0f9667..860ebcb 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
@@ -2,7 +2,38 @@
import android.content.Context
import android.util.AttributeSet
+import android.view.View
import android.widget.FrameLayout
+import com.android.systemui.compose.ComposeFacade
-/** A view that can serve as the root of the main SysUI window. */
-open class WindowRootView(context: Context?, attrs: AttributeSet?) : FrameLayout(context, attrs)
\ No newline at end of file
+/** A view that can serve as the root of the main SysUI window. */
+open class WindowRootView(
+ context: Context,
+ attrs: AttributeSet?,
+) :
+ FrameLayout(
+ context,
+ attrs,
+ ) {
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+
+ if (ComposeFacade.isComposeAvailable() && isRoot()) {
+ ComposeFacade.composeInitializer().onAttachedToWindow(this)
+ }
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+
+ if (ComposeFacade.isComposeAvailable() && isRoot()) {
+ ComposeFacade.composeInitializer().onDetachedFromWindow(this)
+ }
+ }
+
+ private fun isRoot(): Boolean {
+ // TODO(b/283300105): remove this check once there's only one subclass of WindowRootView.
+ return parent.let { it !is View || it.id == android.R.id.content }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 2e47ab6..24fe7d5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -42,8 +42,8 @@
.setSourceCrop(crop)
.build()
val syncScreenCapture = ScreenCapture.createSyncCaptureListener()
- windowManager.captureDisplay(displayId, captureArgs, syncScreenCapture.first)
- val buffer = syncScreenCapture.second.get()
+ windowManager.captureDisplay(displayId, captureArgs, syncScreenCapture)
+ val buffer = syncScreenCapture.getBuffer()
return buffer?.asBitmap()
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
index e0b9f9b..4cc2f62 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperService.java
@@ -20,7 +20,7 @@
import android.content.Intent;
import android.os.IBinder;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
-import android.window.ScreenCapture.ScreenshotSync;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import androidx.annotation.Nullable;
@@ -59,9 +59,9 @@
return null;
}
- ScreenshotSync screenshotSync =
+ SynchronousScreenCaptureListener screenshotSync =
mOptionalBubbles.get().getScreenshotExcludingBubble(displayId);
- ScreenshotHardwareBuffer screenshotHardwareBuffer = screenshotSync.get();
+ ScreenshotHardwareBuffer screenshotHardwareBuffer = screenshotSync.getBuffer();
if (screenshotHardwareBuffer == null) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
index 7e0f504..a9b3d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
@@ -31,8 +31,7 @@
val constraintAlpha = if (visible) 0f else 1f
return ConstraintsChanges(
qqsConstraintsChanges = {
- setAlpha(R.id.statusIcons, constraintAlpha)
- setAlpha(R.id.batteryRemainingIcon, constraintAlpha)
+ setAlpha(R.id.shade_header_system_icons, constraintAlpha)
}
)
}
@@ -45,14 +44,15 @@
R.id.barrier,
ConstraintSet.START,
0,
- R.id.statusIcons,
+ R.id.shade_header_system_icons,
R.id.privacy_container
)
- connect(R.id.statusIcons, ConstraintSet.START, R.id.date, ConstraintSet.END)
+ connect(R.id.shade_header_system_icons, ConstraintSet.START, R.id.date,
+ ConstraintSet.END)
connect(R.id.privacy_container, ConstraintSet.START, R.id.date, ConstraintSet.END)
- constrainWidth(R.id.statusIcons, ViewGroup.LayoutParams.WRAP_CONTENT)
+ constrainWidth(R.id.shade_header_system_icons, ViewGroup.LayoutParams.WRAP_CONTENT)
constrainedWidth(R.id.date, true)
- constrainedWidth(R.id.statusIcons, true)
+ constrainedWidth(R.id.shade_header_system_icons, true)
}
)
}
@@ -84,7 +84,7 @@
setGuidelineEnd(centerEnd, offsetFromEdge)
connect(R.id.date, ConstraintSet.END, centerStart, ConstraintSet.START)
connect(
- R.id.statusIcons,
+ R.id.shade_header_system_icons,
ConstraintSet.START,
centerEnd,
ConstraintSet.END
@@ -96,7 +96,7 @@
ConstraintSet.END
)
constrainedWidth(R.id.date, true)
- constrainedWidth(R.id.statusIcons, true)
+ constrainedWidth(R.id.shade_header_system_icons, true)
},
qsConstraintsChanges = {
setGuidelineBegin(centerStart, offsetFromEdge)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 6d00a2a..e83b7f1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -114,6 +114,8 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -126,12 +128,10 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.shared.model.WakefulnessModel;
@@ -224,8 +224,6 @@
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -236,6 +234,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -1034,7 +1034,7 @@
new NsslHeightChangedListener());
mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener(
mOnEmptySpaceClickListener);
- mQsController.initNotificationStackScrollLayoutController();
+ mQsController.init();
mShadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged);
mShadeHeadsUpTracker.addTrackingHeadsUpListener(
mNotificationStackScrollLayoutController::setTrackingHeadsUp);
@@ -1822,6 +1822,7 @@
// Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
setClosing(true);
+ mUpdateFlingOnLayout = false;
if (delayed) {
mNextCollapseSpeedUpFactor = speedUpFactor;
this.mView.postDelayed(mFlingCollapseRunnable, 120);
@@ -2475,7 +2476,8 @@
alpha = getFadeoutAlpha();
}
if (mBarState == KEYGUARD && !mHintAnimationRunning
- && !mKeyguardBypassController.getBypassEnabled()) {
+ && !mKeyguardBypassController.getBypassEnabled()
+ && !mQsController.getFullyExpanded()) {
alpha *= mClockPositionResult.clockAlpha;
}
mNotificationStackScrollLayoutController.setAlpha(alpha);
@@ -4821,7 +4823,9 @@
if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch(
event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) {
- mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
+ if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+ mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
+ }
return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -4835,7 +4839,6 @@
}
handled |= handleTouch(event);
- mShadeLog.logOnTouchEventLastReturn(event, !mDozing, handled);
return !mDozing || handled;
}
@@ -5022,7 +5025,6 @@
}
break;
}
- mShadeLog.logHandleTouchLastReturn(event, !mGestureWaitForTouchSlop, mTracking);
return !mGestureWaitForTouchSlop || mTracking;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
index c9122c7..2b62b7d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
@@ -58,7 +58,6 @@
import com.android.internal.view.FloatingActionMode;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import com.android.systemui.R;
-import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.scene.ui.view.WindowRootView;
/**
@@ -149,18 +148,6 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setWillNotDraw(!DEBUG);
-
- if (ComposeFacade.INSTANCE.isComposeAvailable()) {
- ComposeFacade.INSTANCE.composeInitializer().onAttachedToWindow(this);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (ComposeFacade.INSTANCE.isComposeAvailable()) {
- ComposeFacade.INSTANCE.composeInitializer().onDetachedFromWindow(this);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c4b74fc..5c41d57 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -40,23 +40,25 @@
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
+import com.android.systemui.back.domain.interactor.BackActionInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
+import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
-import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.log.BouncerLogger;
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor;
import com.android.systemui.multishade.domain.interactor.MultiShadeMotionEventInteractor;
import com.android.systemui.multishade.ui.view.MultiShadeView;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -111,6 +113,8 @@
private NotificationStackScrollLayout mStackScrollLayout;
private PhoneStatusBarViewController mStatusBarViewController;
private final CentralSurfaces mService;
+ private final BackActionInteractor mBackActionInteractor;
+ private final PowerInteractor mPowerInteractor;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private DragDownHelper mDragDownHelper;
private boolean mExpandingBelowNotch;
@@ -144,6 +148,8 @@
StatusBarWindowStateController statusBarWindowStateController,
LockIconViewController lockIconViewController,
CentralSurfaces centralSurfaces,
+ BackActionInteractor backActionInteractor,
+ PowerInteractor powerInteractor,
NotificationShadeWindowController controller,
Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -173,8 +179,10 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mStatusBarWindowStateController = statusBarWindowStateController;
mLockIconViewController = lockIconViewController;
+ mBackActionInteractor = backActionInteractor;
mLockIconViewController.init();
mService = centralSurfaces;
+ mPowerInteractor = powerInteractor;
mNotificationShadeWindowController = controller;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mAmbientState = ambientState;
@@ -307,8 +315,7 @@
/* onGestureDetectedRunnable */
() -> {
mService.userActivity();
- mService.wakeUpIfDozing(
- mClock.uptimeMillis(),
+ mPowerInteractor.wakeUpIfDozing(
"LOCK_ICON_TOUCH",
PowerManager.WAKE_REASON_GESTURE);
}
@@ -443,7 +450,7 @@
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
if (!down) {
- mService.onBackPressed();
+ mBackActionInteractor.onBackRequested();
}
return true;
case KeyEvent.KEYCODE_MENU:
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
index 7dff6ea..e5b84bd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
@@ -55,6 +55,7 @@
private Consumer<QS> mQSFragmentAttachedListener = qs -> {};
private QS mQs;
private View mQSContainer;
+ private int mLastQSPaddingBottom;
/**
* These are used to compute the bounding box containing the shade and the notification scrim,
@@ -83,6 +84,10 @@
mQs = (QS) fragment;
mQSFragmentAttachedListener.accept(mQs);
mQSContainer = mQs.getView().findViewById(R.id.quick_settings_container);
+ // We need to restore the bottom padding as the fragment may have been recreated due to
+ // some special Configuration change, so we apply the last known padding (this will be
+ // correct even if it has changed while the fragment was destroyed and re-created).
+ setQSContainerPaddingBottom(mLastQSPaddingBottom);
}
@Override
@@ -109,6 +114,7 @@
}
public void setQSContainerPaddingBottom(int paddingBottom) {
+ mLastQSPaddingBottom = paddingBottom;
if (mQSContainer != null) {
mQSContainer.setPadding(
mQSContainer.getPaddingLeft(),
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index 9b797a7..ee4e98e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -22,6 +22,7 @@
import android.view.GestureDetector
import android.view.MotionEvent
import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
@@ -29,7 +30,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
import java.io.PrintWriter
@@ -44,9 +44,8 @@
* screen is still ON and not in the true AoD display state. When the device is in the true AoD
* display state, wake-ups are handled by [com.android.systemui.doze.DozeSensors].
*/
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
class PulsingGestureListener @Inject constructor(
- private val notificationShadeWindowView: NotificationShadeWindowView,
private val falsingManager: FalsingManager,
private val dockManager: DockManager,
private val powerInteractor: PowerInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 6480164..1361c9f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -78,6 +78,7 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.data.repository.ShadeRepository;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -101,6 +102,7 @@
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.LargeScreenUtils;
+import com.android.systemui.util.kotlin.JavaAdapter;
import dagger.Lazy;
@@ -153,6 +155,8 @@
private final FeatureFlags mFeatureFlags;
private final InteractionJankMonitor mInteractionJankMonitor;
private final ShadeRepository mShadeRepository;
+ private final ShadeInteractor mShadeInteractor;
+ private final JavaAdapter mJavaAdapter;
private final FalsingManager mFalsingManager;
private final AccessibilityManager mAccessibilityManager;
private final MetricsLogger mMetricsLogger;
@@ -342,6 +346,8 @@
DumpManager dumpManager,
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
ShadeRepository shadeRepository,
+ ShadeInteractor shadeInteractor,
+ JavaAdapter javaAdapter,
CastController castController
) {
mPanelViewControllerLazy = panelViewControllerLazy;
@@ -387,6 +393,8 @@
mFeatureFlags = featureFlags;
mInteractionJankMonitor = interactionJankMonitor;
mShadeRepository = shadeRepository;
+ mShadeInteractor = shadeInteractor;
+ mJavaAdapter = javaAdapter;
mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback());
dumpManager.registerDumpable(this);
@@ -459,7 +467,13 @@
}
// TODO (b/265054088): move this and others to a CoreStartable
- void initNotificationStackScrollLayoutController() {
+ void init() {
+ initNotificationStackScrollLayoutController();
+ mJavaAdapter.alwaysCollectFlow(
+ mShadeInteractor.isExpandToQsEnabled(), this::setExpansionEnabledPolicy);
+ }
+
+ private void initNotificationStackScrollLayoutController() {
mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
new NsslOverscrollTopChangedListener());
mNotificationStackScrollLayoutController.setOnStackYChanged(this::onStackYChanged);
@@ -780,7 +794,6 @@
/** update Qs height state */
public void setExpansionHeight(float height) {
- checkCorrectSplitShadeState(height);
int maxHeight = getMaxExpansionHeight();
height = Math.min(Math.max(
height, getMinExpansionHeight()), maxHeight);
@@ -802,14 +815,6 @@
}
}
- /** TODO(b/269742565) Remove this logging */
- private void checkCorrectSplitShadeState(float height) {
- if (mSplitShadeEnabled && height == 0
- && mPanelViewControllerLazy.get().isShadeFullyExpanded()) {
- Log.wtfStack(TAG, "qsExpansion set to 0 while split shade is expanding or open");
- }
- }
-
/** */
public void setHeightOverrideToDesiredHeight() {
if (isSizeChangeAnimationRunning() && isQsFragmentCreated()) {
@@ -892,7 +897,7 @@
}
/** */
- public void setExpansionEnabledPolicy(boolean expansionEnabledPolicy) {
+ private void setExpansionEnabledPolicy(boolean expansionEnabledPolicy) {
mExpansionEnabledPolicy = expansionEnabledPolicy;
if (mQs != null) {
mQs.setHeaderClickable(isExpansionEnabled());
@@ -1186,7 +1191,6 @@
mClippingAnimationEndBounds.left, fraction);
int animTop = (int) MathUtils.lerp(startTop,
mClippingAnimationEndBounds.top, fraction);
- logClippingTopBound("interpolated top bound", top);
int animRight = (int) MathUtils.lerp(startRight,
mClippingAnimationEndBounds.right, fraction);
int animBottom = (int) MathUtils.lerp(startBottom,
@@ -1216,7 +1220,8 @@
if (mIsFullWidth) {
clipStatusView = qsVisible;
float screenCornerRadius =
- mRecordingController.isRecording() || mCastController.hasConnectedCastDevice()
+ !mSplitShadeEnabled || mRecordingController.isRecording()
+ || mCastController.hasConnectedCastDevice()
? 0 : mScreenCornerRadius;
radius = (int) MathUtils.lerp(screenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
@@ -1337,8 +1342,6 @@
// the screen without clipping.
return -mAmbientState.getStackTopMargin();
} else {
- logNotificationsClippingTopBound(qsTop,
- mNotificationStackScrollLayoutController.getTop());
return qsTop - mNotificationStackScrollLayoutController.getTop();
}
}
@@ -1380,25 +1383,21 @@
keyguardNotificationStaticPadding, maxQsPadding) : maxQsPadding;
topPadding = (int) MathUtils.lerp((float) getMinExpansionHeight(),
(float) max, expandedFraction);
- logNotificationsTopPadding("keyguard and expandImmediate", topPadding);
return topPadding;
} else if (isSizeChangeAnimationRunning()) {
topPadding = Math.max((int) mSizeChangeAnimator.getAnimatedValue(),
keyguardNotificationStaticPadding);
- logNotificationsTopPadding("size change animation running", topPadding);
return topPadding;
} else if (keyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
topPadding = MathUtils.lerp((float) keyguardNotificationStaticPadding,
(float) (getMaxExpansionHeight()), computeExpansionFraction());
- logNotificationsTopPadding("keyguard", topPadding);
return topPadding;
} else {
topPadding = Math.max(mQsFrameTranslateController.getNotificationsTopPadding(
mExpansionHeight, mNotificationStackScrollLayoutController),
mQuickQsHeaderHeight);
- logNotificationsTopPadding("default case", topPadding);
return topPadding;
}
}
@@ -1446,38 +1445,6 @@
- mAmbientState.getScrollY());
}
- /** TODO(b/273591201): remove after bug resolved */
- private void logNotificationsTopPadding(String message, float rawPadding) {
- int padding = ((int) rawPadding / 10) * 10;
- if (mBarState != KEYGUARD && padding != mLastNotificationsTopPadding && !mExpanded) {
- mLastNotificationsTopPadding = padding;
- mShadeLog.logNotificationsTopPadding(message, padding);
- }
- }
-
- /** TODO(b/273591201): remove after bug resolved */
- private void logClippingTopBound(String message, int top) {
- top = (top / 10) * 10;
- if (mBarState != KEYGUARD && mShadeExpandedFraction == 1
- && top != mLastClippingTopBound && !mExpanded) {
- mLastClippingTopBound = top;
- mShadeLog.logClippingTopBound(message, top);
- }
- }
-
- /** TODO(b/273591201): remove after bug resolved */
- private void logNotificationsClippingTopBound(int top, int nsslTop) {
- top = (top / 10) * 10;
- nsslTop = (nsslTop / 10) * 10;
- if (mBarState == SHADE && mShadeExpandedFraction == 1
- && (top != mLastNotificationsClippingTopBound
- || nsslTop != mLastNotificationsClippingTopBoundNssl) && !mExpanded) {
- mLastNotificationsClippingTopBound = top;
- mLastNotificationsClippingTopBoundNssl = nsslTop;
- mShadeLog.logNotificationsClippingTopBound(top, nsslTop);
- }
- }
-
private int calculateTopClippingBound(int qsPanelBottomY) {
int top;
if (mSplitShadeEnabled) {
@@ -1487,7 +1454,6 @@
// If we're transitioning, let's use the actual value. The else case
// can be wrong during transitions when waiting for the keyguard to unlock
top = mTransitionToFullShadePosition;
- logClippingTopBound("set while transitioning to full shade", top);
} else {
final float notificationTop = getEdgePosition();
if (mBarState == KEYGUARD) {
@@ -1496,10 +1462,8 @@
// this should go away once we unify the stackY position and don't have
// to do this min anymore below.
top = qsPanelBottomY;
- logClippingTopBound("bypassing keyguard", top);
} else {
top = (int) Math.min(qsPanelBottomY, notificationTop);
- logClippingTopBound("keyguard default case", top);
}
} else {
top = (int) notificationTop;
@@ -1507,14 +1471,12 @@
}
// TODO (b/265193930): remove dependency on NPVC
top += mPanelViewControllerLazy.get().getOverStretchAmount();
- logClippingTopBound("including overstretch", top);
// Correction for instant expansion caused by HUN pull down/
float minFraction = mPanelViewControllerLazy.get().getMinFraction();
if (minFraction > 0f && minFraction < 1f) {
float realFraction = (mShadeExpandedFraction
- minFraction) / (1f - minFraction);
top *= MathUtils.saturate(realFraction / minFraction);
- logClippingTopBound("after adjusted fraction", top);
}
}
return top;
@@ -1654,15 +1616,11 @@
// as sometimes the qsExpansionFraction can be a tiny value instead of 0 when in QQS.
if (!mSplitShadeEnabled && !mLastShadeFlingWasExpanding
&& computeExpansionFraction() <= 0.01 && mShadeExpandedFraction < 1.0) {
- mShadeLog.logMotionEvent(event,
- "handleQsTouch: shade touched while shade collapsing, QS tracking disabled");
mTracking = false;
}
if (!isExpandImmediate() && mTracking) {
onTouch(event);
if (!mConflictingExpansionGesture && !mSplitShadeEnabled) {
- mShadeLog.logMotionEvent(event,
- "handleQsTouch: not immediate expand or conflicting gesture");
return true;
}
}
@@ -1756,7 +1714,6 @@
break;
case MotionEvent.ACTION_MOVE:
- mShadeLog.logMotionEvent(event, "onQsTouch: move action, setting QS expansion");
setExpansionHeight(h + mInitialHeightOnTouch);
// TODO (b/265193930): remove dependency on NPVC
if (h >= mPanelViewControllerLazy.get().getFalsingThreshold()) {
@@ -1844,17 +1801,14 @@
final float h = y - mInitialTouchY;
trackMovement(event);
if (mTracking) {
-
// Already tracking because onOverscrolled was called. We need to update here
// so we don't stop for a frame until the next touch event gets handled in
// onTouchEvent.
setExpansionHeight(h + mInitialHeightOnTouch);
trackMovement(event);
return true;
- } else {
- mShadeLog.logMotionEvent(event,
- "onQsIntercept: move ignored because qs tracking disabled");
}
+
// TODO (b/265193930): remove dependency on NPVC
float touchSlop = event.getClassification()
== MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
@@ -1878,7 +1832,7 @@
} else {
mShadeLog.logQsTrackingNotStarted(mInitialTouchY, y, h, touchSlop,
getExpanded(), mPanelViewControllerLazy.get().isKeyguardShowing(),
- isExpansionEnabled());
+ isExpansionEnabled(), event.getDownTime());
}
break;
@@ -1939,7 +1893,7 @@
target = getMaxExpansionHeight();
break;
case FLING_COLLAPSE:
- if (mSplitShadeEnabled) { // TODO:(b/269742565) remove below log
+ if (mSplitShadeEnabled) {
Log.wtfStack(TAG, "FLING_COLLAPSE called in split shade");
}
setExpandImmediate(false);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 2b772e3..2da8d5f4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -54,7 +54,8 @@
touchSlop: Float,
qsExpanded: Boolean,
keyguardShowing: Boolean,
- qsExpansionEnabled: Boolean
+ qsExpansionEnabled: Boolean,
+ downTime: Long
) {
buffer.log(
TAG,
@@ -67,10 +68,11 @@
bool1 = qsExpanded
bool2 = keyguardShowing
bool3 = qsExpansionEnabled
+ str1 = downTime.toString()
},
{
- "QsTrackingNotStarted: initTouchY=$int1,y=$int2,h=$long1,slop=$double1,qsExpanded" +
- "=$bool1,keyguardShowing=$bool2,qsExpansion=$bool3"
+ "QsTrackingNotStarted: downTime=$str1,initTouchY=$int1,y=$int2,h=$long1," +
+ "slop=$double1,qsExpanded=$bool1,keyguardShowing=$bool2,qsExpansion=$bool3"
}
)
}
@@ -306,91 +308,6 @@
)
}
- fun logNotificationsTopPadding(message: String, padding: Int) {
- buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- str1 = message
- int1 = padding
- },
- { "QSC NotificationsTopPadding $str1: $int1"}
- )
- }
-
- fun logClippingTopBound(message: String, top: Int) {
- buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- str1 = message
- int1 = top
- },
- { "QSC ClippingTopBound $str1: $int1" }
- )
- }
-
- fun logNotificationsClippingTopBound(top: Int, nsslTop: Int) {
- buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- int1 = top
- int2 = nsslTop
- },
- { "QSC NotificationsClippingTopBound set to $int1 - $int2" }
- )
- }
-
- fun logOnTouchEventLastReturn(
- event: MotionEvent,
- dozing: Boolean,
- handled: Boolean,
- ) {
- buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- bool1 = dozing
- bool2 = handled
- long1 = event.eventTime
- long2 = event.downTime
- int1 = event.action
- int2 = event.classification
- double1 = event.y.toDouble()
- },
- {
- "NPVC onTouchEvent last return: !mDozing: $bool1 || handled: $bool2 " +
- "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
- }
- )
- }
-
- fun logHandleTouchLastReturn(
- event: MotionEvent,
- gestureWaitForTouchSlop: Boolean,
- tracking: Boolean,
- ) {
- buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- bool1 = gestureWaitForTouchSlop
- bool2 = tracking
- long1 = event.eventTime
- long2 = event.downTime
- int1 = event.action
- int2 = event.classification
- double1 = event.y.toDouble()
- },
- {
- "NPVC handleTouch last return: !mGestureWaitForTouchSlop: $bool1 " +
- "|| mTracking: $bool2 " +
- "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
- }
- )
- }
-
fun logUpdateNotificationPanelTouchState(
disabled: Boolean,
isGoingToSleep: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 4b2a65f..3686b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.annotation.SuppressLint
import android.content.ContentResolver
import android.os.Handler
import android.view.LayoutInflater
@@ -28,6 +29,7 @@
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.biometrics.AuthRippleView
+import com.android.systemui.compose.ComposeFacade
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
@@ -67,13 +69,16 @@
companion object {
const val SHADE_HEADER = "large_screen_shade_header"
+ @SuppressLint("InflateParams") // Root views don't have parents.
@Provides
@SysUISingleton
fun providesWindowRootView(
layoutInflater: LayoutInflater,
featureFlags: FeatureFlags,
): WindowRootView {
- return if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ return if (
+ featureFlags.isEnabled(Flags.SCENE_CONTAINER) && ComposeFacade.isComposeAvailable()
+ ) {
layoutInflater.inflate(R.layout.scene_window_root, null)
} else {
layoutInflater.inflate(R.layout.super_notification_shade, null)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 5ac36bf..8d5c30b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -36,33 +36,12 @@
headsUpManager: HeadsUpManagerPhone
)
- /**
- * Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If
- * in split shade, it will collapse the whole shade.
- *
- * @param fullyCollapse Do not stop when QS becomes QQS. Fling until QS isn't visible anymore.
- */
- fun animateCollapseQs(fullyCollapse: Boolean)
-
- /** Returns whether the shade can be collapsed. */
- fun canBeCollapsed(): Boolean
-
/** Cancels any pending collapses. */
fun cancelPendingCollapse()
/** Cancels the views current animation. */
fun cancelAnimation()
- /**
- * Close the keyguard user switcher if it is open and capable of closing.
- *
- * Has no effect if user switcher isn't supported, if the user switcher is already closed, or if
- * the user switcher uses "simple" mode. The simple user switcher cannot be closed.
- *
- * @return true if the keyguard user switcher was open, and is now closed
- */
- fun closeUserSwitcherIfOpen(): Boolean
-
/** Input focus transfer is about to happen. */
fun startWaitingForExpandGesture()
@@ -116,9 +95,6 @@
/** Sets the view's alpha to max. */
fun resetAlpha()
- /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */
- fun onBackPressed()
-
/** Sets progress of the predictive back animation. */
fun onBackProgressed(progressFraction: Float)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 9c80e02..05d2bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -77,6 +77,17 @@
/** Collapses the shade with an animation duration in milliseconds. */
fun collapseWithDuration(animationDuration: Int)
+ /**
+ * Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If
+ * in split shade, it will collapse the whole shade.
+ *
+ * @param fullyCollapse Do not stop when QS becomes QQS. Fling until QS isn't visible anymore.
+ */
+ fun animateCollapseQs(fullyCollapse: Boolean)
+
+ /** Returns whether the shade can be collapsed. */
+ fun canBeCollapsed(): Boolean
+
/** Returns whether the shade is in the process of collapsing. */
val isCollapsing: Boolean
@@ -126,6 +137,19 @@
/** Sets the amount of progress in the status bar launch animation. */
fun applyLaunchAnimationProgress(linearProgress: Float)
+ /**
+ * Close the keyguard user switcher if it is open and capable of closing.
+ *
+ * Has no effect if user switcher isn't supported, if the user switcher is already closed, or if
+ * the user switcher uses "simple" mode. The simple user switcher cannot be closed.
+ *
+ * @return true if the keyguard user switcher was open, and is now closed
+ */
+ fun closeUserSwitcherIfOpen(): Boolean
+
+ /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */
+ fun onBackPressed()
+
/** Sets whether the status bar launch animation is currently running. */
fun setIsLaunchAnimationRunning(running: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index fc1e87a..ad49b26 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -198,6 +198,11 @@
return mSlotIndexResolver.getSlotIndex(subscriptionId);
}
+ @VisibleForTesting
+ protected int getShadeCarrierVisibility(int index) {
+ return mCarrierGroups[index].getVisibility();
+ }
+
/**
* Sets a {@link OnSingleCarrierChangedListener}.
*
@@ -307,11 +312,13 @@
+ info.subscriptionIds[i]);
continue;
}
- mInfos[slot] = mInfos[slot].changeVisibility(true);
- slotSeen[slot] = true;
- mCarrierGroups[slot].setCarrierText(
- info.listOfCarriers[i].toString().trim());
- mCarrierGroups[slot].setVisibility(View.VISIBLE);
+ String carrierText = info.listOfCarriers[i].toString().trim();
+ if (!TextUtils.isEmpty(carrierText)) {
+ mInfos[slot] = mInfos[slot].changeVisibility(true);
+ slotSeen[slot] = true;
+ mCarrierGroups[slot].setCarrierText(carrierText);
+ mCarrierGroups[slot].setVisibility(View.VISIBLE);
+ }
}
for (int i = 0; i < SIM_SLOTS; i++) {
if (!slotSeen[i]) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
new file mode 100644
index 0000000..eceda84
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shade.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.domain.interactor.UserInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+
+/** Business logic for shade interactions. */
+@SysUISingleton
+class ShadeInteractor
+@Inject
+constructor(
+ disableFlagsRepository: DisableFlagsRepository,
+ keyguardRepository: KeyguardRepository,
+ userSetupRepository: UserSetupRepository,
+ deviceProvisionedController: DeviceProvisionedController,
+ userInteractor: UserInteractor,
+) {
+ /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
+ val isExpandToQsEnabled: Flow<Boolean> =
+ combine(
+ disableFlagsRepository.disableFlags,
+ keyguardRepository.isDozing,
+ userSetupRepository.isUserSetupFlow,
+ ) { disableFlags, isDozing, isUserSetup ->
+ deviceProvisionedController.isDeviceProvisioned &&
+ // Disallow QS during setup if it's a simple user switcher. (The user intends to
+ // use the lock screen user switcher, QS is not needed.)
+ (isUserSetup || !userInteractor.isSimpleUserSwitcher) &&
+ disableFlags.isShadeEnabled() &&
+ disableFlags.isQuickSettingsEnabled() &&
+ !isDozing
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index a532195..6c2c0cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -19,7 +19,6 @@
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
-import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
@@ -37,7 +36,7 @@
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.os.Binder;
@@ -226,8 +225,10 @@
* @param backDisposition Disposition mode of back button. It should be one of below flags:
* @param showImeSwitcher {@code true} to show IME switch button.
*/
- default void setImeWindowStatus(int displayId, IBinder token, int vis,
- @BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
+ default void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
+ boolean showImeSwitcher) { }
default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleTaskbar() { }
@@ -678,7 +679,9 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ public void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
@@ -1092,7 +1095,9 @@
}
}
- private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
+ private void handleShowImeButton(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
boolean showImeSwitcher) {
if (displayId == INVALID_DISPLAY) return;
@@ -1112,7 +1117,7 @@
private void sendImeInvisibleStatusForPrevNavBar() {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId,
- null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT,
+ null /* token */, 0 /* vis */, BACK_DISPOSITION_DEFAULT,
false /* showImeSwitcher */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 926d9b8..795bcad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -91,6 +91,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -226,6 +227,7 @@
// triggered while the device is asleep
private final AlarmTimeout mHideTransientMessageHandler;
private final AlarmTimeout mHideBiometricMessageHandler;
+ private FeatureFlags mFeatureFlags;
/**
* Creates a new KeyguardIndicationController and registers callbacks.
@@ -256,7 +258,8 @@
AlternateBouncerInteractor alternateBouncerInteractor,
AlarmManager alarmManager,
UserTracker userTracker,
- BouncerMessageInteractor bouncerMessageInteractor
+ BouncerMessageInteractor bouncerMessageInteractor,
+ FeatureFlags flags
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -282,6 +285,8 @@
mAlternateBouncerInteractor = alternateBouncerInteractor;
mUserTracker = userTracker;
mBouncerMessageInteractor = bouncerMessageInteractor;
+ mFeatureFlags = flags;
+
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
int[] msgIds = context.getResources().getIntArray(
@@ -345,7 +350,8 @@
mLockScreenIndicationView,
mExecutor,
mStatusBarStateController,
- mKeyguardLogger
+ mKeyguardLogger,
+ mFeatureFlags
);
updateDeviceEntryIndication(false /* animate */);
updateOrganizedOwnedDevice();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
index dcd9dc3..4ec5f46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
@@ -52,7 +52,7 @@
mActivatableNotificationViewController = activatableNotificationViewController;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
- mView.setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM));
+ mView.setSensitiveRevealAnimEnabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM));
mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index c098f45..e2d2ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -6,7 +6,6 @@
import android.content.Context
import android.content.res.Configuration
import android.os.PowerManager
-import android.os.SystemClock
import android.util.IndentingPrintWriter
import android.util.MathUtils
import android.view.MotionEvent
@@ -30,6 +29,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -76,6 +76,7 @@
dumpManager: DumpManager,
qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
private val shadeRepository: ShadeRepository,
+ private val powerInteractor: PowerInteractor,
) : Dumpable {
private var pulseHeight: Float = 0f
@get:VisibleForTesting
@@ -278,11 +279,7 @@
// Bind the click listener of the shelf to go to the full shade
notificationShelfController.setOnClickListener {
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(),
- "SHADE_CLICK",
- PowerManager.WAKE_REASON_GESTURE,
- )
+ powerInteractor.wakeUpIfDozing("SHADE_CLICK", PowerManager.WAKE_REASON_GESTURE)
goToLockedShade(it)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index c519115..da84afe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -27,7 +27,6 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
@@ -52,6 +51,7 @@
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.RemoteInputControllerLogger;
@@ -60,19 +60,15 @@
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.ListenerSet;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.Optional;
import java.util.function.Consumer;
/**
@@ -95,10 +91,8 @@
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final SmartReplyController mSmartReplyController;
private final NotificationVisibilityProvider mVisibilityProvider;
+ private final PowerInteractor mPowerInteractor;
private final ActionClickLogger mLogger;
-
- private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
-
protected final Context mContext;
protected final NotifPipelineFlags mNotifPipelineFlags;
private final UserManager mUserManager;
@@ -122,10 +116,8 @@
@Override
public boolean onInteraction(
View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
- mCentralSurfacesOptionalLazy.get().ifPresent(
- centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
- PowerManager.WAKE_REASON_GESTURE));
+ mPowerInteractor.wakeUpIfDozing(
+ "NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE);
final NotificationEntry entry = getNotificationForParent(view.getParent());
mLogger.logInitialClick(entry, pendingIntent);
@@ -259,7 +251,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
+ PowerInteractor powerInteractor,
StatusBarStateController statusBarStateController,
RemoteInputUriController remoteInputUriController,
RemoteInputControllerLogger remoteInputControllerLogger,
@@ -271,7 +263,7 @@
mLockscreenUserManager = lockscreenUserManager;
mSmartReplyController = smartReplyController;
mVisibilityProvider = visibilityProvider;
- mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
+ mPowerInteractor = powerInteractor;
mLogger = logger;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -402,7 +394,7 @@
while (p != null) {
if (p instanceof View) {
View pv = (View) p;
- if (pv.isRootNamespace()) {
+ if (pv.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
riv = findRemoteInputView(pv);
row = (ExpandableNotificationRow) pv.getTag(R.id.row_tag_for_content_view);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index edf37ef..25a1dc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -95,7 +95,7 @@
private float mCornerAnimationDistance;
private NotificationShelfController mController;
private float mActualWidth = -1;
- private boolean mSensitiveRevealAnimEndabled;
+ private boolean mSensitiveRevealAnimEnabled;
private boolean mShelfRefactorFlagEnabled;
private boolean mCanModifyColorOfNotifications;
private boolean mCanInteract;
@@ -261,21 +261,21 @@
viewState.hidden = true;
}
}
-
- final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
- if (mSensitiveRevealAnimEndabled && viewState.hidden) {
- // if the shelf is hidden, position it at the end of the stack (plus the clip
- // padding), such that when it appears animated, it will smoothly move in from the
- // bottom, without jump cutting any notifications
- viewState.setYTranslation(stackEnd + mPaddingBetweenElements);
- } else {
- viewState.setYTranslation(stackEnd - viewState.height);
- }
} else {
viewState.hidden = true;
viewState.location = ExpandableViewState.LOCATION_GONE;
viewState.hasItemsInStableShelf = false;
}
+
+ final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
+ if (mSensitiveRevealAnimEnabled && viewState.hidden) {
+ // if the shelf is hidden, position it at the end of the stack (plus the clip
+ // padding), such that when it appears animated, it will smoothly move in from the
+ // bottom, without jump cutting any notifications
+ viewState.setYTranslation(stackEnd + mPaddingBetweenElements);
+ } else {
+ viewState.setYTranslation(stackEnd - viewState.height);
+ }
}
private int getSpeedBumpIndex() {
@@ -413,7 +413,7 @@
expandingAnimated, isLastChild, shelfClipStart);
// TODO(b/172289889) scale mPaddingBetweenElements with expansion amount
- if ((!mSensitiveRevealAnimEndabled && ((isLastChild && !child.isInShelf())
+ if ((!mSensitiveRevealAnimEnabled && ((isLastChild && !child.isInShelf())
|| backgroundForceHidden)) || aboveShelf) {
notificationClipEnd = shelfStart + getIntrinsicHeight();
} else {
@@ -462,7 +462,7 @@
// if the shelf is visible, but if the shelf is hidden, it causes incorrect curling.
// notificationClipEnd handles the discrepancy between a visible and hidden shelf,
// so we use that when on the keyguard (and while animating away) to reduce curling.
- final float keyguardSafeShelfStart = !mSensitiveRevealAnimEndabled
+ final float keyguardSafeShelfStart = !mSensitiveRevealAnimEnabled
&& mAmbientState.isOnKeyguard() ? notificationClipEnd : shelfStart;
updateCornerRoundnessOnScroll(anv, viewStart, keyguardSafeShelfStart);
}
@@ -1064,8 +1064,8 @@
* Set whether the sensitive reveal animation feature flag is enabled
* @param enabled true if enabled
*/
- public void setSensitiveRevealAnimEndabled(boolean enabled) {
- mSensitiveRevealAnimEndabled = enabled;
+ public void setSensitiveRevealAnimEnabled(boolean enabled) {
+ mSensitiveRevealAnimEnabled = enabled;
}
public void setRefactorFlagEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 73eba0e..075b41b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -28,6 +28,7 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.AnimationFeatureFlags;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -35,10 +36,10 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
import com.android.systemui.statusbar.ActionClickLogger;
@@ -79,14 +80,14 @@
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-
import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
+import java.util.Optional;
+import java.util.concurrent.Executor;
+
/**
* This module provides instances needed to construct {@link CentralSurfacesImpl}. These are moved to
* this separate from {@link CentralSurfacesModule} module so that components that wish to build
@@ -104,7 +105,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
+ PowerInteractor powerInteractor,
StatusBarStateController statusBarStateController,
RemoteInputUriController remoteInputUriController,
RemoteInputControllerLogger remoteInputControllerLogger,
@@ -117,7 +118,7 @@
lockscreenUserManager,
smartReplyController,
visibilityProvider,
- centralSurfacesOptionalLazy,
+ powerInteractor,
statusBarStateController,
remoteInputUriController,
remoteInputControllerLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
index f04159c..dc86869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
@@ -71,15 +71,14 @@
}
/**
- * Returns a string representing the, old, new, and new-after-modification disable flag states,
- * as well as the differences between each of the states.
+ * Returns a string representing the new and new-after-modification disable flag states,
+ * as well as the differences between them (if there are any).
*
- * Example if [old], [new], and [newAfterLocalModification] are all different:
- * Old: EnaiHbcRso.qINgr | New: EnaihBcRso.qiNGR (changed: hB.iGR) | New after local
- * modification: EnaihBcRso.qInGR (changed: .n)
+ * Example if [new] and [newAfterLocalModification] are different:
+ * New: EnaihBcRso.qiNGR | New after local modification: EnaihBCRso.qInGR (changed: C.In)
*
- * Example if [old] and [new] are the same:
- * EnaihBcRso.qiNGR (unchanged)
+ * Example if [new] and [newAfterLocalModification] are the same:
+ * New: EnaihBcRso.qiNGR
*
* A capital character signifies the flag is set and a lowercase character signifies that the
* flag isn't set. The flag states will be logged in the same order as the passed-in lists.
@@ -88,37 +87,17 @@
* is no difference. the new-after-modification state also won't be included if there's no
* difference from the new state.
*
- * @param old the disable state that had been previously sent. Null if we don't need to log the
- * previously sent state.
* @param new the new disable state that has just been sent.
* @param newAfterLocalModification the new disable states after a class has locally modified
* them. Null if the class does not locally modify.
*/
fun getDisableFlagsString(
- old: DisableState? = null,
new: DisableState,
newAfterLocalModification: DisableState? = null
): String {
val builder = StringBuilder("Received new disable state: ")
- // This if/else has slightly repetitive code but is easier to read.
- if (old != null && old != new) {
- builder.append("Old: ")
- builder.append(getFlagsString(old))
- builder.append(" | ")
- builder.append("New: ")
- builder.append(getFlagsString(new))
- builder.append(" ")
- builder.append(getDiffString(old, new))
- } else if (old != null && old == new) {
- // If old and new are the same, we only need to print one of them.
- builder.append(getFlagsString(new))
- builder.append(" ")
- builder.append(getDiffString(old, new))
- } else { // old == null
- builder.append(getFlagsString(new))
- // Don't get a diff string because we have no [old] to compare with.
- }
+ builder.append(getFlagsString(new))
if (newAfterLocalModification != null && new != newAfterLocalModification) {
builder.append(" | New after local modification: ")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/dagger/DisableFlagsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/dagger/DisableFlagsModule.kt
new file mode 100644
index 0000000..3d5f8df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/dagger/DisableFlagsModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.dagger
+
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+/** Provides information related to disable flags. */
+@Module
+abstract class DisableFlagsModule {
+ @Binds
+ abstract fun bindDisableFlagsRepo(impl: DisableFlagsRepositoryImpl): DisableFlagsRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
new file mode 100644
index 0000000..ac05248
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.data.model
+
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE_NONE
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
+
+/**
+ * Model for the disable flags that come from [IStatusBar].
+ *
+ * For clients of the disable flags: do *not* refer to the disable integers directly. Instead,
+ * re-use or define a helper method that internally processes the flags. (We want to hide the
+ * bitwise logic here so no one else has to worry about it.)
+ */
+data class DisableFlagsModel(
+ private val disable1: Int = DISABLE_NONE,
+ private val disable2: Int = DISABLE2_NONE,
+) {
+ /** Returns true if notification alerts are allowed based on the flags. */
+ fun areNotificationAlertsEnabled(): Boolean {
+ return (disable1 and DISABLE_NOTIFICATION_ALERTS) == 0
+ }
+
+ /** Returns true if the shade is allowed based on the flags. */
+ fun isShadeEnabled(): Boolean {
+ return (disable2 and DISABLE2_NOTIFICATION_SHADE) == 0
+ }
+
+ /** Returns true if full quick settings are allowed based on the flags. */
+ fun isQuickSettingsEnabled(): Boolean {
+ return (disable2 and DISABLE2_QUICK_SETTINGS) == 0
+ }
+
+ /** Logs the change to the provided buffer. */
+ fun logChange(buffer: LogBuffer, disableFlagsLogger: DisableFlagsLogger) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = disable1
+ int2 = disable2
+ },
+ {
+ disableFlagsLogger.getDisableFlagsString(
+ new = DisableFlagsLogger.DisableState(int1, int2),
+ )
+ }
+ )
+ }
+
+ private companion object {
+ const val TAG = "DisableFlagsModel"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
new file mode 100644
index 0000000..13b74b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.dagger.DisableFlagsRepositoryLog
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/** Repository for the disable flags received from external systems. See [IStatusBar.disable]. */
+interface DisableFlagsRepository {
+ /** A model of the disable flags last received from [IStatusBar]. */
+ val disableFlags: StateFlow<DisableFlagsModel>
+}
+
+@SysUISingleton
+class DisableFlagsRepositoryImpl
+@Inject
+constructor(
+ commandQueue: CommandQueue,
+ @DisplayId private val thisDisplayId: Int,
+ @Application scope: CoroutineScope,
+ remoteInputQuickSettingsDisabler: RemoteInputQuickSettingsDisabler,
+ @DisableFlagsRepositoryLog private val logBuffer: LogBuffer,
+ private val disableFlagsLogger: DisableFlagsLogger,
+) : DisableFlagsRepository {
+ override val disableFlags: StateFlow<DisableFlagsModel> =
+ conflatedCallbackFlow {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun disable(
+ displayId: Int,
+ state1: Int,
+ state2: Int,
+ animate: Boolean,
+ ) {
+ if (displayId != thisDisplayId) {
+ return
+ }
+ trySend(
+ DisableFlagsModel(
+ state1,
+ // Ideally, [RemoteInputQuickSettingsDisabler] should instead
+ // expose a flow that gets `combine`d with this [disableFlags]
+ // flow in a [DisableFlagsInteractor] or
+ // [QuickSettingsInteractor]-type class. However, that's out of
+ // scope for the CentralSurfaces removal project.
+ remoteInputQuickSettingsDisabler.adjustDisableFlags(state2),
+ )
+ )
+ }
+ }
+ commandQueue.addCallback(callback)
+ awaitClose { commandQueue.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+ .onEach { it.logChange(logBuffer, disableFlagsLogger) }
+ // Use Eagerly because we always need to know about disable flags
+ .stateIn(scope, SharingStarted.Eagerly, DisableFlagsModel())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index cf39038..8778463 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -176,7 +176,16 @@
now.isBefore(Instant.ofEpochMilli(t.expiryTimeMillis))
}
if (weatherTarget != null) {
- val weatherData = WeatherData.fromBundle(weatherTarget.baseAction.extras)
+ val clickIntent = weatherTarget.headerAction?.intent
+ val weatherData = WeatherData.fromBundle(weatherTarget.baseAction.extras, { v ->
+ if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ activityStarter.startActivity(
+ clickIntent,
+ true, /* dismissShade */
+ null,
+ false)
+ }
+ })
if (weatherData != null) {
keyguardUpdateMonitor.sendWeatherData(weatherData)
}
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 bab553e..d10fac6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -17,15 +17,14 @@
import android.app.Notification;
import android.os.PowerManager;
-import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
import com.android.systemui.DejankUtils;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
@@ -40,7 +39,7 @@
private static final String TAG = "NotificationClicker";
private final NotificationClickerLogger mLogger;
- private final Optional<CentralSurfaces> mCentralSurfacesOptional;
+ private final PowerInteractor mPowerInteractor;
private final Optional<Bubbles> mBubblesOptional;
private final NotificationActivityStarter mNotificationActivityStarter;
@@ -54,11 +53,11 @@
private NotificationClicker(
NotificationClickerLogger logger,
- Optional<CentralSurfaces> centralSurfacesOptional,
+ PowerInteractor powerInteractor,
Optional<Bubbles> bubblesOptional,
NotificationActivityStarter notificationActivityStarter) {
mLogger = logger;
- mCentralSurfacesOptional = centralSurfacesOptional;
+ mPowerInteractor = powerInteractor;
mBubblesOptional = bubblesOptional;
mNotificationActivityStarter = notificationActivityStarter;
}
@@ -70,9 +69,7 @@
return;
}
- mCentralSurfacesOptional.ifPresent(centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
- PowerManager.WAKE_REASON_GESTURE));
+ mPowerInteractor.wakeUpIfDozing("NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE);
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
final NotificationEntry entry = row.getEntry();
@@ -131,21 +128,22 @@
/** Daggerized builder for NotificationClicker. */
public static class Builder {
private final NotificationClickerLogger mLogger;
+ private final PowerInteractor mPowerInteractor;
@Inject
- public Builder(NotificationClickerLogger logger) {
+ public Builder(NotificationClickerLogger logger, PowerInteractor powerInteractor) {
mLogger = logger;
+ mPowerInteractor = powerInteractor;
}
/** Builds an instance. */
public NotificationClicker build(
- Optional<CentralSurfaces> centralSurfacesOptional,
Optional<Bubbles> bubblesOptional,
NotificationActivityStarter notificationActivityStarter
) {
return new NotificationClicker(
mLogger,
- centralSurfacesOptional,
+ mPowerInteractor,
bubblesOptional,
notificationActivityStarter);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index b116246..2796340 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -61,6 +61,7 @@
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
@@ -274,6 +275,7 @@
Assert.isMainThread();
checkForReentrantCall();
+ final int entryCount = entriesToDismiss.size();
final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>();
for (int i = 0; i < entriesToDismiss.size(); i++) {
NotificationEntry entry = entriesToDismiss.get(i).first;
@@ -282,28 +284,34 @@
requireNonNull(stats);
NotificationEntry storedEntry = mNotificationSet.get(entry.getKey());
if (storedEntry == null) {
- mLogger.logNonExistentNotifDismissed(entry);
+ mLogger.logDismissNonExistentNotif(entry, i, entryCount);
continue;
}
if (entry != storedEntry) {
throw mEulogizer.record(
new IllegalStateException("Invalid entry: "
+ "different stored and dismissed entries for " + logKey(entry)
+ + " (" + i + "/" + entryCount + ")"
+ + " dismissed=@" + Integer.toHexString(entry.hashCode())
+ " stored=@" + Integer.toHexString(storedEntry.hashCode())));
}
if (entry.getDismissState() == DISMISSED) {
+ mLogger.logDismissAlreadyDismissedNotif(entry, i, entryCount);
continue;
+ } else if (entry.getDismissState() == PARENT_DISMISSED) {
+ mLogger.logDismissAlreadyParentDismissedNotif(entry, i, entryCount);
}
updateDismissInterceptors(entry);
if (isDismissIntercepted(entry)) {
- mLogger.logNotifDismissedIntercepted(entry);
+ mLogger.logNotifDismissedIntercepted(entry, i, entryCount);
continue;
}
entriesToLocallyDismiss.add(entry);
if (!entry.isCanceled()) {
+ int finalI = i;
// send message to system server if this notification hasn't already been cancelled
mBgExecutor.execute(() -> {
try {
@@ -316,7 +324,7 @@
stats.notificationVisibility);
} catch (RemoteException e) {
// system process is dead if we're here.
- mLogger.logRemoteExceptionOnNotificationClear(entry, e);
+ mLogger.logRemoteExceptionOnNotificationClear(entry, finalI, entryCount, e);
}
});
}
@@ -353,14 +361,16 @@
}
final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs());
+ final int initialEntryCount = entries.size();
for (int i = entries.size() - 1; i >= 0; i--) {
NotificationEntry entry = entries.get(i);
+
if (!shouldDismissOnClearAll(entry, userId)) {
// system server won't be removing these notifications, but we still give dismiss
// interceptors the chance to filter the notification
updateDismissInterceptors(entry);
if (isDismissIntercepted(entry)) {
- mLogger.logNotifClearAllDismissalIntercepted(entry);
+ mLogger.logNotifClearAllDismissalIntercepted(entry, i, initialEntryCount);
}
entries.remove(i);
}
@@ -376,25 +386,46 @@
*/
private void locallyDismissNotifications(List<NotificationEntry> entries) {
final List<NotificationEntry> canceledEntries = new ArrayList<>();
-
+ final int entryCount = entries.size();
for (int i = 0; i < entries.size(); i++) {
NotificationEntry entry = entries.get(i);
+ final NotificationEntry storedEntry = mNotificationSet.get(entry.getKey());
+ if (storedEntry == null) {
+ mLogger.logLocallyDismissNonExistentNotif(entry, i, entryCount);
+ } else if (storedEntry != entry) {
+ mLogger.logLocallyDismissMismatchedEntry(entry, i, entryCount, storedEntry);
+ }
+
+ if (entry.getDismissState() == DISMISSED) {
+ mLogger.logLocallyDismissAlreadyDismissedNotif(entry, i, entryCount);
+ } else if (entry.getDismissState() == PARENT_DISMISSED) {
+ mLogger.logLocallyDismissAlreadyParentDismissedNotif(entry, i, entryCount);
+ }
+
entry.setDismissState(DISMISSED);
- mLogger.logNotifDismissed(entry);
+ mLogger.logLocallyDismissed(entry, i, entryCount);
if (entry.isCanceled()) {
canceledEntries.add(entry);
- } else {
- // Mark any children as dismissed as system server will auto-dismiss them as well
- if (entry.getSbn().getNotification().isGroupSummary()) {
- for (NotificationEntry otherEntry : mNotificationSet.values()) {
- if (shouldAutoDismissChildren(otherEntry, entry.getSbn().getGroupKey())) {
- otherEntry.setDismissState(PARENT_DISMISSED);
- mLogger.logChildDismissed(otherEntry);
- if (otherEntry.isCanceled()) {
- canceledEntries.add(otherEntry);
- }
+ continue;
+ }
+
+ // Mark any children as dismissed as system server will auto-dismiss them as well
+ if (entry.getSbn().getNotification().isGroupSummary()) {
+ for (NotificationEntry otherEntry : mNotificationSet.values()) {
+ if (shouldAutoDismissChildren(otherEntry, entry.getSbn().getGroupKey())) {
+ if (otherEntry.getDismissState() == DISMISSED) {
+ mLogger.logLocallyDismissAlreadyDismissedChild(
+ otherEntry, entry, i, entryCount);
+ } else if (otherEntry.getDismissState() == PARENT_DISMISSED) {
+ mLogger.logLocallyDismissAlreadyParentDismissedChild(
+ otherEntry, entry, i, entryCount);
+ }
+ otherEntry.setDismissState(PARENT_DISMISSED);
+ mLogger.logLocallyDismissedChild(otherEntry, entry, i, entryCount);
+ if (otherEntry.isCanceled()) {
+ canceledEntries.add(otherEntry);
}
}
}
@@ -404,7 +435,7 @@
// Immediately remove any dismissed notifs that have already been canceled by system server
// (probably due to being lifetime-extended up until this point).
for (NotificationEntry canceledEntry : canceledEntries) {
- mLogger.logDismissOnAlreadyCanceledEntry(canceledEntry);
+ mLogger.logLocallyDismissedAlreadyCanceledEntry(canceledEntry);
tryRemoveNotification(canceledEntry);
}
}
@@ -513,10 +544,16 @@
* @return True if the notification was removed, false otherwise.
*/
private boolean tryRemoveNotification(NotificationEntry entry) {
- if (mNotificationSet.get(entry.getKey()) != entry) {
+ final NotificationEntry storedEntry = mNotificationSet.get(entry.getKey());
+ if (storedEntry == null) {
+ Log.wtf(TAG, "TRY REMOVE non-existent notification " + logKey(entry));
+ return false;
+ } else if (storedEntry != entry) {
throw mEulogizer.record(
- new IllegalStateException("No notification to remove with key "
- + logKey(entry)));
+ new IllegalStateException("Mismatched stored and tryRemoved entries"
+ + " for key " + logKey(entry) + ":"
+ + " stored=@" + Integer.toHexString(storedEntry.hashCode())
+ + " tryRemoved=@" + Integer.toHexString(entry.hashCode())));
}
if (!entry.isCanceled()) {
@@ -730,14 +767,16 @@
}
private void cancelLocalDismissal(NotificationEntry entry) {
- if (entry.getDismissState() != NOT_DISMISSED) {
- entry.setDismissState(NOT_DISMISSED);
- if (entry.getSbn().getNotification().isGroupSummary()) {
- for (NotificationEntry otherEntry : mNotificationSet.values()) {
- if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey())
- && otherEntry.getDismissState() == PARENT_DISMISSED) {
- otherEntry.setDismissState(NOT_DISMISSED);
- }
+ if (entry.getDismissState() == NOT_DISMISSED) {
+ mLogger.logCancelLocalDismissalNotDismissedNotif(entry);
+ return;
+ }
+ entry.setDismissState(NOT_DISMISSED);
+ if (entry.getSbn().getNotification().isGroupSummary()) {
+ for (NotificationEntry otherEntry : mNotificationSet.values()) {
+ if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey())
+ && otherEntry.getDismissState() == PARENT_DISMISSED) {
+ otherEntry.setDismissState(NOT_DISMISSED);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 38c3723..1896080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -140,7 +140,6 @@
.expandableNotificationRow(row)
.notificationEntry(entry)
.onExpandClickListener(mPresenter)
- .listContainer(mListContainer)
.build();
ExpandableNotificationRowController rowController =
component.getExpandableNotificationRowController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 20de785..73227ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -108,27 +108,39 @@
})
}
- fun logNotifDismissed(entry: NotificationEntry) {
+ fun logLocallyDismissed(entry: NotificationEntry, index: Int, count: Int) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
+ int1 = index
+ int2 = count
}, {
- "DISMISSED $str1"
+ "LOCALLY DISMISSED $str1 ($int1/$int2)"
})
}
- fun logNonExistentNotifDismissed(entry: NotificationEntry) {
+ fun logDismissNonExistentNotif(entry: NotificationEntry, index: Int, count: Int) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
+ int1 = index
+ int2 = count
}, {
- "DISMISSED Non Existent $str1"
+ "DISMISS Non Existent $str1 ($int1/$int2)"
})
}
- fun logChildDismissed(entry: NotificationEntry) {
+ fun logLocallyDismissedChild(
+ child: NotificationEntry,
+ parent: NotificationEntry,
+ parentIndex: Int,
+ parentCount: Int
+ ) {
buffer.log(TAG, DEBUG, {
- str1 = entry.logKey
+ str1 = child.logKey
+ str2 = parent.logKey
+ int1 = parentIndex
+ int2 = parentCount
}, {
- "CHILD DISMISSED (inferred): $str1"
+ "LOCALLY DISMISSED CHILD (inferred): $str1 of parent $str2 ($int1/$int2)"
})
}
@@ -140,27 +152,31 @@
})
}
- fun logDismissOnAlreadyCanceledEntry(entry: NotificationEntry) {
+ fun logLocallyDismissedAlreadyCanceledEntry(entry: NotificationEntry) {
buffer.log(TAG, DEBUG, {
str1 = entry.logKey
}, {
- "Dismiss on $str1, which was already canceled. Trying to remove..."
+ "LOCALLY DISMISSED Already Canceled $str1. Trying to remove."
})
}
- fun logNotifDismissedIntercepted(entry: NotificationEntry) {
+ fun logNotifDismissedIntercepted(entry: NotificationEntry, index: Int, count: Int) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
+ int1 = index
+ int2 = count
}, {
- "DISMISS INTERCEPTED $str1"
+ "DISMISS INTERCEPTED $str1 ($int1/$int2)"
})
}
- fun logNotifClearAllDismissalIntercepted(entry: NotificationEntry) {
+ fun logNotifClearAllDismissalIntercepted(entry: NotificationEntry, index: Int, count: Int) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
+ int1 = index
+ int2 = count
}, {
- "CLEAR ALL DISMISSAL INTERCEPTED $str1"
+ "CLEAR ALL DISMISSAL INTERCEPTED $str1 ($int1/$int2)"
})
}
@@ -251,12 +267,19 @@
})
}
- fun logRemoteExceptionOnNotificationClear(entry: NotificationEntry, e: RemoteException) {
+ fun logRemoteExceptionOnNotificationClear(
+ entry: NotificationEntry,
+ index: Int,
+ count: Int,
+ e: RemoteException
+ ) {
buffer.log(TAG, WTF, {
str1 = entry.logKey
+ int1 = index
+ int2 = count
str2 = e.toString()
}, {
- "RemoteException while attempting to clear $str1:\n$str2"
+ "RemoteException while attempting to clear $str1 ($int1/$int2):\n$str2"
})
}
@@ -387,6 +410,126 @@
"Mismatch: current $str2 is $str3 for: $str1"
})
}
+
+ fun logDismissAlreadyDismissedNotif(entry: NotificationEntry, index: Int, count: Int) {
+ buffer.log(TAG, DEBUG, {
+ str1 = entry.logKey
+ int1 = index
+ int2 = count
+ }, {
+ "DISMISS Already Dismissed $str1 ($int1/$int2)"
+ })
+ }
+
+ fun logDismissAlreadyParentDismissedNotif(
+ childEntry: NotificationEntry,
+ childIndex: Int,
+ childCount: Int
+ ) {
+ buffer.log(TAG, DEBUG, {
+ str1 = childEntry.logKey
+ int1 = childIndex
+ int2 = childCount
+ str2 = childEntry.parent?.summary?.logKey ?: "(null)"
+ }, {
+ "DISMISS Already Parent-Dismissed $str1 ($int1/$int2) with summary $str2"
+ })
+ }
+
+ fun logLocallyDismissNonExistentNotif(entry: NotificationEntry, index: Int, count: Int) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ int1 = index
+ int2 = count
+ }, {
+ "LOCALLY DISMISS Non Existent $str1 ($int1/$int2)"
+ })
+ }
+
+ fun logLocallyDismissMismatchedEntry(
+ entry: NotificationEntry,
+ index: Int,
+ count: Int,
+ storedEntry: NotificationEntry
+ ) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ int1 = index
+ int2 = count
+ str2 = Integer.toHexString(entry.hashCode())
+ str3 = Integer.toHexString(storedEntry.hashCode())
+ }, {
+ "LOCALLY DISMISS Mismatch $str1 ($int1/$int2): dismissing @$str2 but stored @$str3"
+ })
+ }
+
+ fun logLocallyDismissAlreadyDismissedNotif(
+ entry: NotificationEntry,
+ index: Int,
+ count: Int
+ ) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ int1 = index
+ int2 = count
+ }, {
+ "LOCALLY DISMISS Already Dismissed $str1 ($int1/$int2)"
+ })
+ }
+
+ fun logLocallyDismissAlreadyParentDismissedNotif(
+ entry: NotificationEntry,
+ index: Int,
+ count: Int
+ ) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ int1 = index
+ int2 = count
+ }, {
+ "LOCALLY DISMISS Already Dismissed $str1 ($int1/$int2)"
+ })
+ }
+
+ fun logLocallyDismissAlreadyDismissedChild(
+ childEntry: NotificationEntry,
+ parentEntry: NotificationEntry,
+ parentIndex: Int,
+ parentCount: Int
+ ) {
+ buffer.log(TAG, INFO, {
+ str1 = childEntry.logKey
+ str2 = parentEntry.logKey
+ int1 = parentIndex
+ int2 = parentCount
+ }, {
+ "LOCALLY DISMISS Already Dismissed Child $str1 of parent $str2 ($int1/$int2)"
+ })
+ }
+
+ fun logLocallyDismissAlreadyParentDismissedChild(
+ childEntry: NotificationEntry,
+ parentEntry: NotificationEntry,
+ parentIndex: Int,
+ parentCount: Int
+ ) {
+ buffer.log(TAG, INFO, {
+ str1 = childEntry.logKey
+ str2 = parentEntry.logKey
+ int1 = parentIndex
+ int2 = parentCount
+ }, {
+ "LOCALLY DISMISS Already Parent-Dismissed Child $str1 of parent $str2 ($int1/$int2)"
+ })
+ }
+
+ fun logCancelLocalDismissalNotDismissedNotif(entry: NotificationEntry) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ }, {
+ "CANCEL LOCAL DISMISS Not Dismissed $str1"
+ })
+ }
}
private const val TAG = "NotifCollection"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 731ec80..d47fe20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -63,10 +63,27 @@
* - has a media session associated with it
* - has messaging style
*
- * A GroupEntry is considered high priority if its representativeEntry (summary) or children are
- * high priority
+ * A GroupEntry is considered high priority if its representativeEntry (summary) or any of its
+ * children are high priority.
*/
public boolean isHighPriority(@Nullable ListEntry entry) {
+ return isHighPriority(entry, /* allowImplicit = */ true);
+ }
+
+ /**
+ * @return true if the ListEntry is explicitly high priority, else false
+ *
+ * A NotificationEntry is considered explicitly high priority if has importance greater than or
+ * equal to IMPORTANCE_DEFAULT.
+ *
+ * A GroupEntry is considered explicitly high priority if its representativeEntry (summary) or
+ * any of its children are explicitly high priority.
+ */
+ public boolean isExplicitlyHighPriority(@Nullable ListEntry entry) {
+ return isHighPriority(entry, /* allowImplicit= */ false);
+ }
+
+ private boolean isHighPriority(@Nullable ListEntry entry, boolean allowImplicit) {
if (entry == null) {
return false;
}
@@ -77,8 +94,8 @@
}
return notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || hasHighPriorityCharacteristics(notifEntry)
- || hasHighPriorityChild(entry);
+ || (allowImplicit && hasHighPriorityCharacteristics(notifEntry))
+ || hasHighPriorityChild(entry, allowImplicit);
}
/**
@@ -112,7 +129,7 @@
>= NotificationManager.IMPORTANCE_DEFAULT);
}
- private boolean hasHighPriorityChild(ListEntry entry) {
+ private boolean hasHighPriorityChild(ListEntry entry, boolean allowImplicit) {
if (entry instanceof NotificationEntry
&& !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) {
return false;
@@ -121,7 +138,7 @@
List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry);
if (children != null) {
for (NotificationEntry child : children) {
- if (child != entry && isHighPriority(child)) {
+ if (child != entry && isHighPriority(child, allowImplicit)) {
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index b100d44..31d4ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -63,8 +63,12 @@
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import dagger.Binds;
@@ -85,6 +89,8 @@
ShadeEventsModule.class,
NotifPipelineChoreographerModule.class,
NotificationSectionHeadersModule.class,
+ NotificationListViewModelModule.class,
+ ActivatableNotificationViewModelModule.class,
})
public interface NotificationsModule {
@Binds
@@ -159,6 +165,14 @@
}
}
+ /** Provides the container for the notification list. */
+ @Provides
+ @SysUISingleton
+ static NotificationListContainer provideListContainer(
+ NotificationStackScrollLayoutController nsslController) {
+ return nsslController.getNotificationListContainer();
+ }
+
/**
* Provide the active notification collection managing the notifications to render.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt
new file mode 100644
index 0000000..8f7e269
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import javax.inject.Inject
+
+/** Interactor for notifications in general. */
+@SysUISingleton
+class NotificationsInteractor
+@Inject
+constructor(
+ private val disableFlagsRepository: DisableFlagsRepository,
+) {
+ /** Returns true if notification alerts are allowed. */
+ fun areNotificationAlertsEnabled(): Boolean {
+ return disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled()
+ }
+}
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 c9ebed1..76e228b 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
@@ -22,7 +22,6 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.CentralSurfaces
/**
* The master controller for all notifications-related work
@@ -32,7 +31,6 @@
*/
interface NotificationsController {
fun initialize(
- centralSurfaces: CentralSurfaces,
presenter: NotificationPresenter,
listContainer: NotificationListContainer,
stackController: NotifStackController,
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 6409635..f7bd177 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
@@ -42,7 +42,6 @@
import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.wm.shell.bubbles.Bubbles
import dagger.Lazy
import java.util.Optional
@@ -78,7 +77,6 @@
) : NotificationsController {
override fun initialize(
- centralSurfaces: CentralSurfaces,
presenter: NotificationPresenter,
listContainer: NotificationListContainer,
stackController: NotifStackController,
@@ -93,9 +91,7 @@
})
notificationRowBinder.setNotificationClicker(
- clickerBuilder.build(
- Optional.ofNullable(centralSurfaces), bubblesOptional,
- notificationActivityStarter))
+ clickerBuilder.build(bubblesOptional, notificationActivityStarter))
notificationRowBinder.setUpWithPresenter(presenter, listContainer)
headsUpViewBinder.setPresenter(presenter)
notifBindPipelineInitializer.initialize()
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 302a1f4..65ba6de 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
@@ -23,7 +23,6 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.CentralSurfaces
import javax.inject.Inject
/**
@@ -34,7 +33,6 @@
) : NotificationsController {
override fun initialize(
- centralSurfaces: CentralSurfaces,
presenter: NotificationPresenter,
listContainer: NotificationListContainer,
stackController: NotifStackController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
index 7513aa7..90014c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -180,8 +180,8 @@
}
private fun shouldHideIfEntrySilent(entry: ListEntry): Boolean = when {
- // Show if high priority (not hidden)
- highPriorityProvider.isHighPriority(entry) -> false
+ // Show if explicitly high priority (not hidden)
+ highPriorityProvider.isExplicitlyHighPriority(entry) -> false
// Ambient notifications are hidden always from lock screen
entry.representativeEntry?.isAmbient == true -> true
// [Now notification is silent]
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 417d4ac..8af488e 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
@@ -321,8 +321,7 @@
protected void setBackgroundTintColor(int color) {
if (color != mCurrentBackgroundTint) {
mCurrentBackgroundTint = color;
- // TODO(282173943): re-enable this tinting optimization when Resources are thread-safe
- if (false && color == mNormalColor) {
+ if (color == mNormalColor) {
// We don't need to tint a normal notification
color = 0;
}
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 9f397fe..30747db 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
@@ -53,6 +53,7 @@
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -103,6 +104,8 @@
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -170,6 +173,7 @@
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private Optional<BubblesManager> mBubblesManagerOptional;
private MetricsLogger mMetricsLogger;
+ private NotificationChildrenContainerLogger mChildrenContainerLogger;
private NotificationDismissibilityProvider mDismissibilityProvider;
private FeatureFlags mFeatureFlags;
private int mIconTransformContentShift;
@@ -1627,6 +1631,51 @@
NotificationEntry child,
NotificationEntry newParent
);
+
+ /**
+ * Called when an ExpandableNotificationRow transient view is removed from the
+ * NotificationChildrenContainer
+ */
+ void logRemoveTransientFromContainer(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry
+ );
+
+ /**
+ * Called when an ExpandableNotificationRow transient view is removed from the
+ * NotificationStackScrollLayout
+ */
+ void logRemoveTransientFromNssl(
+ NotificationEntry childEntry
+ );
+
+ /**
+ * Called when an ExpandableNotificationRow transient view is removed from a ViewGroup that
+ * is not NotificationChildrenContainer or NotificationStackScrollLayout
+ */
+ void logRemoveTransientFromViewGroup(
+ NotificationEntry childEntry,
+ ViewGroup containerView
+ );
+
+ /**
+ * Called when an ExpandableNotificationRow transient view is added to this
+ * ExpandableNotificationRow
+ */
+ void logAddTransientRow(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry,
+ int index
+ );
+
+ /**
+ * Called when an ExpandableNotificationRow transient view is removed from this
+ * ExpandableNotificationRow
+ */
+ void logRemoveTransientRow(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry
+ );
}
/**
@@ -1668,6 +1717,7 @@
NotificationGutsManager gutsManager,
NotificationDismissibilityProvider dismissibilityProvider,
MetricsLogger metricsLogger,
+ NotificationChildrenContainerLogger childrenContainerLogger,
SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController,
FeatureFlags featureFlags,
@@ -1706,6 +1756,7 @@
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
mMetricsLogger = metricsLogger;
+ mChildrenContainerLogger = childrenContainerLogger;
mDismissibilityProvider = dismissibilityProvider;
mFeatureFlags = featureFlags;
}
@@ -1874,6 +1925,7 @@
mChildrenContainer.setIsLowPriority(mIsLowPriority);
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
+ mChildrenContainer.setLogger(mChildrenContainerLogger);
mTranslateableViews.add(mChildrenContainer);
});
@@ -2673,7 +2725,12 @@
}
public boolean isExpanded(boolean allowOnKeyguard) {
- return (!mOnKeyguard || allowOnKeyguard)
+ if (DEBUG) {
+ if (!mShowingPublicInitialized && !allowOnKeyguard) {
+ Log.d(TAG, "mShowingPublic is not initialized.");
+ }
+ }
+ return !mShowingPublic && (!mOnKeyguard || allowOnKeyguard)
&& (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
|| isUserExpanded());
}
@@ -3620,6 +3677,8 @@
pw.print(", mOnUserInteractionCallback null: " + (mOnUserInteractionCallback == null));
pw.print(", removed: " + isRemoved());
pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
+ pw.print(", mShowingPublic: " + mShowingPublic);
+ pw.print(", mShowingPublicInitialized: " + mShowingPublicInitialized);
NotificationContentView showingLayout = getShowingLayout();
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
pw.println();
@@ -3707,4 +3766,73 @@
public boolean getShowSnooze() {
return mShowSnooze;
}
+
+ @Override
+ public void removeFromTransientContainer() {
+ final ViewGroup transientContainer = getTransientContainer();
+ final ViewParent parent = getParent();
+ // Only log when there is real removal of transient views
+ if (transientContainer == null || transientContainer != parent) {
+ super.removeFromTransientContainer();
+ return;
+ }
+ logRemoveFromTransientContainer(transientContainer);
+ super.removeFromTransientContainer();
+ }
+
+ /**
+ * Log calls to removeFromTransientContainer when the container is NotificationChildrenContainer
+ * or NotificationStackScrollLayout.
+ */
+ public void logRemoveFromTransientContainer(ViewGroup transientContainer) {
+ if (mLogger == null) {
+ return;
+ }
+ if (transientContainer instanceof NotificationChildrenContainer) {
+ mLogger.logRemoveTransientFromContainer(
+ /* childEntry = */ getEntry(),
+ /* containerEntry = */ ((NotificationChildrenContainer) transientContainer)
+ .getContainingNotification().getEntry()
+ );
+ } else if (transientContainer instanceof NotificationStackScrollLayout) {
+ mLogger.logRemoveTransientFromNssl(
+ /* childEntry = */ getEntry()
+ );
+ } else {
+ mLogger.logRemoveTransientFromViewGroup(
+ /* childEntry = */ getEntry(),
+ /* containerView = */ transientContainer
+ );
+ }
+ }
+
+ @Override
+ public void addTransientView(View view, int index) {
+ if (view instanceof ExpandableNotificationRow) {
+ logAddTransientRow((ExpandableNotificationRow) view, index);
+ }
+ super.addTransientView(view, index);
+ }
+
+ private void logAddTransientRow(ExpandableNotificationRow row, int index) {
+ if (mLogger == null) {
+ return;
+ }
+ mLogger.logAddTransientRow(row.getEntry(), getEntry(), index);
+ }
+
+ @Override
+ public void removeTransientView(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ logRemoveTransientRow((ExpandableNotificationRow) view);
+ }
+ super.removeTransientView(view);
+ }
+
+ private void logRemoveTransientRow(ExpandableNotificationRow row) {
+ if (mLogger == null) {
+ return;
+ }
+ mLogger.logRemoveTransientRow(row.getEntry(), getEntry());
+ }
}
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 1acc9f9..a4e8c2e 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
@@ -50,6 +50,7 @@
import com.android.systemui.statusbar.notification.row.dagger.AppName;
import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -88,6 +89,7 @@
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
private final MetricsLogger mMetricsLogger;
+ private final NotificationChildrenContainerLogger mChildrenContainerLogger;
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
private final NotificationGutsManager mNotificationGutsManager;
private final OnUserInteractionCallback mOnUserInteractionCallback;
@@ -125,6 +127,46 @@
) {
mLogBufferLogger.logSkipAttachingKeepInParentChild(child, newParent);
}
+
+ @Override
+ public void logRemoveTransientFromContainer(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry
+ ) {
+ mLogBufferLogger.logRemoveTransientFromContainer(childEntry, containerEntry);
+ }
+
+ @Override
+ public void logRemoveTransientFromNssl(
+ NotificationEntry childEntry
+ ) {
+ mLogBufferLogger.logRemoveTransientFromNssl(childEntry);
+ }
+
+ @Override
+ public void logRemoveTransientFromViewGroup(
+ NotificationEntry childEntry,
+ ViewGroup containerView
+ ) {
+ mLogBufferLogger.logRemoveTransientFromViewGroup(childEntry, containerView);
+ }
+
+ @Override
+ public void logAddTransientRow(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry,
+ int index
+ ) {
+ mLogBufferLogger.logAddTransientRow(childEntry, containerEntry, index);
+ }
+
+ @Override
+ public void logRemoveTransientRow(
+ NotificationEntry childEntry,
+ NotificationEntry containerEntry
+ ) {
+ mLogBufferLogger.logRemoveTransientRow(childEntry, containerEntry);
+ }
};
@@ -135,6 +177,7 @@
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
MetricsLogger metricsLogger,
NotificationRowLogger logBufferLogger,
+ NotificationChildrenContainerLogger childrenContainerLogger,
NotificationListContainer listContainer,
SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController,
@@ -188,6 +231,7 @@
mBubblesManagerOptional = bubblesManagerOptional;
mDragController = dragController;
mMetricsLogger = metricsLogger;
+ mChildrenContainerLogger = childrenContainerLogger;
mLogBufferLogger = logBufferLogger;
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
@@ -222,6 +266,7 @@
mNotificationGutsManager,
mDismissibilityProvider,
mMetricsLogger,
+ mChildrenContainerLogger,
mSmartReplyConstants,
mSmartReplyController,
mFeatureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 0989df6..6bbeebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,15 +16,11 @@
package com.android.systemui.statusbar.notification.row;
-import static android.graphics.PorterDuff.Mode.SRC_ATOP;
-
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
@@ -161,20 +157,10 @@
*/
public void updateColors() {
Resources.Theme theme = mContext.getTheme();
- final @ColorInt int textColor = getResources().getColor(R.color.notif_pill_text, theme);
- final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
- final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
- // TODO(b/282173943): Remove redundant tinting once Resources are thread-safe
- final @ColorInt int buttonBgColor =
- Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface);
- final ColorFilter bgColorFilter = new PorterDuffColorFilter(buttonBgColor, SRC_ATOP);
- if (buttonBgColor != 0) {
- clearAllBg.setColorFilter(bgColorFilter);
- manageBg.setColorFilter(bgColorFilter);
- }
- mClearAllButton.setBackground(clearAllBg);
+ int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ mClearAllButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
mClearAllButton.setTextColor(textColor);
- mManageButton.setBackground(manageBg);
+ mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
mManageButton.setTextColor(textColor);
final @ColorInt int labelTextColor =
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index b4bfded..13d1978 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -474,7 +474,6 @@
parentLayout,
remoteViewClickHandler);
validateView(v, entry, row.getResources());
- v.setIsRootNamespace(true);
applyCallback.setResultView(v);
} else {
newContentView.reapply(
@@ -511,7 +510,6 @@
return;
}
if (isNewView) {
- v.setIsRootNamespace(true);
applyCallback.setResultView(v);
} else if (existingWrapper != null) {
existingWrapper.onReinflated();
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 124df8c..20f4429 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
@@ -208,6 +208,23 @@
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
mStatusBarService = statusBarService;
+ // We set root namespace so that we avoid searching children for id. Notification might
+ // contain custom view and their ids may clash with ids already existing in shade or
+ // notification panel
+ setIsRootNamespace(true);
+ }
+
+ @Override
+ public View focusSearch(View focused, int direction) {
+ // This implementation is copied from ViewGroup but with removed special handling of
+ // setIsRootNamespace. This view is set as tree root using setIsRootNamespace and it
+ // causes focus to be stuck inside of it. We need to be root to avoid id conflicts
+ // but we don't want to behave like root when it comes to focusing.
+ if (mParent != null) {
+ return mParent.focusSearch(focused, direction);
+ }
+ Log.wtf(TAG, "NotificationContentView doesn't have parent");
+ return null;
}
public void reinflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
index c3dd92a..89338f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
@@ -17,14 +17,21 @@
package com.android.systemui.statusbar.notification.row
+import android.view.ViewGroup
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
-class NotificationRowLogger @Inject constructor(@NotificationLog private val buffer: LogBuffer) {
+class NotificationRowLogger
+@Inject
+constructor(
+ @NotificationLog private val buffer: LogBuffer,
+ @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
+) {
fun logKeepInParentChildDetached(child: NotificationEntry, oldParent: NotificationEntry?) {
buffer.log(
TAG,
@@ -48,6 +55,79 @@
{ "Skipping to attach $str1 to $str2, because it still flagged to keep in parent" }
)
}
+
+ fun logRemoveTransientFromContainer(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ },
+ { "RemoveTransientRow from ChildrenContainer: childKey: $str1 -- containerKey: $str2" }
+ )
+ }
+
+ fun logRemoveTransientFromNssl(
+ childEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = childEntry.logKey },
+ { "RemoveTransientRow from Nssl: childKey: $str1" }
+ )
+ }
+
+ fun logRemoveTransientFromViewGroup(
+ childEntry: NotificationEntry,
+ containerView: ViewGroup,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.WARNING,
+ {
+ str1 = childEntry.logKey
+ str2 = containerView.toString()
+ },
+ { "RemoveTransientRow from other ViewGroup: childKey: $str1 -- ViewGroup: $str2" }
+ )
+ }
+
+ fun logAddTransientRow(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry,
+ index: Int
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.ERROR,
+ {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ int1 = index
+ },
+ { "addTransientRow to row: childKey: $str1 -- containerKey: $str2 -- index: $int1" }
+ )
+ }
+
+ fun logRemoveTransientRow(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.ERROR,
+ {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ },
+ { "removeTransientRow from row: childKey: $str1 -- containerKey: $str2" }
+ )
+ }
}
private const val TAG = "NotifRow"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
index 1a7417a..3588621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import dagger.Binds;
@@ -59,8 +58,6 @@
Builder notificationEntry(NotificationEntry entry);
@BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
- @BindsInstance
- Builder listContainer(NotificationListContainer listContainer);
ExpandableNotificationRowComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
index 69484b0..4b89615 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
@@ -20,10 +20,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShelf
-import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -35,8 +34,7 @@
constructor(
private val keyguardRepository: KeyguardRepository,
private val deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository,
- private val centralSurfaces: CentralSurfaces,
- private val systemClock: SystemClock,
+ private val powerInteractor: PowerInteractor,
private val keyguardTransitionController: LockscreenShadeTransitionController,
) {
/** Is the shelf showing on the keyguard? */
@@ -55,11 +53,7 @@
/** Transition keyguard to the locked shade, triggered by the shelf. */
fun goToLockedShadeFromShelf() {
- centralSurfaces.wakeUpIfDozing(
- systemClock.uptimeMillis(),
- "SHADE_CLICK",
- PowerManager.WAKE_REASON_GESTURE,
- )
+ powerInteractor.wakeUpIfDozing("SHADE_CLICK", PowerManager.WAKE_REASON_GESTURE)
keyguardTransitionController.goToLockedShade(null)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 2520738..23a58d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -81,7 +81,7 @@
ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
shelf.apply {
setRefactorFlagEnabled(true)
- setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
+ setSensitiveRevealAnimEnabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
// TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
notificationIconAreaController.setShelfIcons(shelfIcons)
repeatWhenAttached {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
index fb19443..5ca8b53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
@@ -16,16 +16,16 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/** ViewModel for [NotificationShelf]. */
-@CentralSurfacesScope
+@SysUISingleton
class NotificationShelfViewModel
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index f8e374d..dad8064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -132,6 +132,8 @@
private boolean mContainingNotificationIsFaded = false;
private RoundableState mRoundableState;
+ private NotificationChildrenContainerLogger mLogger;
+
public NotificationChildrenContainer(Context context) {
this(context, null);
}
@@ -1507,6 +1509,33 @@
return mNotificationHeaderWrapper;
}
+ public void setLogger(NotificationChildrenContainerLogger logger) {
+ mLogger = logger;
+ }
+
+ @Override
+ public void addTransientView(View view, int index) {
+ if (mLogger != null && view instanceof ExpandableNotificationRow) {
+ mLogger.addTransientRow(
+ ((ExpandableNotificationRow) view).getEntry(),
+ getContainingNotification().getEntry(),
+ index
+ );
+ }
+ super.addTransientView(view, index);
+ }
+
+ @Override
+ public void removeTransientView(View view) {
+ if (mLogger != null && view instanceof ExpandableNotificationRow) {
+ mLogger.removeTransientRow(
+ ((ExpandableNotificationRow) view).getEntry(),
+ getContainingNotification().getEntry()
+ );
+ }
+ super.removeTransientView(view);
+ }
+
public String debugString() {
return TAG + " { "
+ "visibility: " + getVisibility()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt
new file mode 100644
index 0000000..6be1ef8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationRenderLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
+import javax.inject.Inject
+
+class NotificationChildrenContainerLogger
+@Inject
+constructor(@NotificationRenderLog private val notificationRenderBuffer: LogBuffer) {
+ fun addTransientRow(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry,
+ index: Int
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ int1 = index
+ },
+ { "addTransientRow: childKey: $str1 -- containerKey: $str2 -- index: $int1" }
+ )
+ }
+
+ fun removeTransientRow(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ },
+ { "removeTransientRow: childKey: $str1 -- containerKey: $str2" }
+ )
+ }
+
+ companion object {
+ private const val TAG = "NotifChildrenContainer"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 0b5e436..479fbdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2759,6 +2759,7 @@
boolean animationGenerated = container != null && generateRemoveAnimation(child);
if (animationGenerated) {
if (!mSwipedOutViews.contains(child) || !isFullySwipedOut(child)) {
+ logAddTransientChild(child, container);
container.addTransientView(child, 0);
child.setTransientContainer(container);
}
@@ -2774,6 +2775,46 @@
focusNextViewIfFocused(child);
}
+ private void logAddTransientChild(ExpandableView child, ViewGroup container) {
+ if (mLogger == null) {
+ return;
+ }
+ if (child instanceof ExpandableNotificationRow) {
+ if (container instanceof NotificationChildrenContainer) {
+ mLogger.addTransientChildNotificationToChildContainer(
+ ((ExpandableNotificationRow) child).getEntry(),
+ ((NotificationChildrenContainer) container)
+ .getContainingNotification().getEntry()
+ );
+ } else if (container instanceof NotificationStackScrollLayout) {
+ mLogger.addTransientChildNotificationToNssl(
+ ((ExpandableNotificationRow) child).getEntry()
+ );
+ } else {
+ mLogger.addTransientChildNotificationToViewGroup(
+ ((ExpandableNotificationRow) child).getEntry(),
+ container
+ );
+ }
+ }
+ }
+
+ @Override
+ public void addTransientView(View view, int index) {
+ if (mLogger != null && view instanceof ExpandableNotificationRow) {
+ mLogger.addTransientRow(((ExpandableNotificationRow) view).getEntry(), index);
+ }
+ super.addTransientView(view, index);
+ }
+
+ @Override
+ public void removeTransientView(View view) {
+ if (mLogger != null && view instanceof ExpandableNotificationRow) {
+ mLogger.removeTransientRow(((ExpandableNotificationRow) view).getEntry());
+ }
+ super.removeTransientView(view);
+ }
+
/**
* Has this view been fully swiped out such that it's not visible anymore.
*/
@@ -3033,7 +3074,9 @@
if (!animationsEnabled) {
mSwipedOutViews.clear();
mChildrenToRemoveAnimated.clear();
- clearTemporaryViewsInGroup(this);
+ clearTemporaryViewsInGroup(
+ /* viewGroup = */ this,
+ /* reason = */ "setAnimationsEnabled");
}
}
@@ -4008,26 +4051,48 @@
private void clearTemporaryViews() {
// lets make sure nothing is transient anymore
- clearTemporaryViewsInGroup(this);
+ clearTemporaryViewsInGroup(
+ /* viewGroup = */ this,
+ /* reason = */ "clearTemporaryViews"
+ );
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = getChildAtIndex(i);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- clearTemporaryViewsInGroup(row.getChildrenContainer());
+ clearTemporaryViewsInGroup(
+ /* viewGroup = */ row.getChildrenContainer(),
+ /* reason = */ "clearTemporaryViewsInGroup(row.getChildrenContainer())"
+ );
}
}
}
- private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
+ private void clearTemporaryViewsInGroup(ViewGroup viewGroup, String reason) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
final View transientView = viewGroup.getTransientView(0);
viewGroup.removeTransientView(transientView);
if (transientView instanceof ExpandableView) {
((ExpandableView) transientView).setTransientContainer(null);
+ if (transientView instanceof ExpandableNotificationRow) {
+ logTransientNotificationRowTraversalCleaned(
+ (ExpandableNotificationRow) transientView,
+ reason
+ );
+ }
}
}
}
+ private void logTransientNotificationRowTraversalCleaned(
+ ExpandableNotificationRow transientView,
+ String reason
+ ) {
+ if (mLogger == null) {
+ return;
+ }
+ mLogger.transientNotificationRowTraversalCleaned(transientView.getEntry(), reason);
+ }
+
void onPanelTrackingStarted() {
mPanelTracking = true;
mAmbientState.setPanelTracking(true);
@@ -5051,6 +5116,9 @@
println(pw, "intrinsicPadding", mIntrinsicPadding);
println(pw, "topPadding", mTopPadding);
println(pw, "bottomPadding", mBottomPadding);
+ println(pw, "translationX", getTranslationX());
+ println(pw, "translationY", getTranslationY());
+ println(pw, "translationZ", getTranslationZ());
mNotificationStackSizeCalculator.dump(pw, args);
});
pw.println();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index aef623a..86b88cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -59,6 +59,7 @@
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -112,14 +113,12 @@
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -142,7 +141,7 @@
/**
* Controller for {@link NotificationStackScrollLayout}.
*/
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
public class NotificationStackScrollLayoutController {
private static final String TAG = "StackScrollerController";
private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
@@ -179,8 +178,6 @@
private final KeyguardInteractor mKeyguardInteractor;
private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
private final NotificationLockscreenUserManager mLockscreenUserManager;
- // TODO: CentralSurfaces should be encapsulated behind a Controller
- private final CentralSurfaces mCentralSurfaces;
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
@@ -645,7 +642,6 @@
FalsingManager falsingManager,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
- CentralSurfaces centralSurfaces,
ScrimController scrimController,
GroupExpansionManager groupManager,
@SilentHeader SectionHeaderController silentHeaderController,
@@ -696,7 +692,6 @@
mFalsingManager = falsingManager;
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
- mCentralSurfaces = centralSurfaces;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
mNotificationStackSizeCalculator = notificationStackSizeCalculator;
@@ -1467,7 +1462,7 @@
return mNotificationRoundnessManager;
}
- NotificationListContainer getNotificationListContainer() {
+ public NotificationListContainer getNotificationListContainer() {
return mNotificationListContainer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java
deleted file mode 100644
index 3dcaae2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutListContainerModule.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.stack;
-
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public abstract class NotificationStackScrollLayoutListContainerModule {
- @Provides
- @CentralSurfacesComponent.CentralSurfacesScope
- static NotificationListContainer provideListContainer(
- NotificationStackScrollLayoutController nsslController) {
- return nsslController.getNotificationListContainer();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 5b0ec1d..9c1bd17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -1,9 +1,12 @@
package com.android.systemui.statusbar.notification.stack
+import android.view.ViewGroup
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD
@@ -15,7 +18,8 @@
import javax.inject.Inject
class NotificationStackScrollLogger @Inject constructor(
- @NotificationHeadsUpLog private val buffer: LogBuffer
+ @NotificationHeadsUpLog private val buffer: LogBuffer,
+ @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
) {
fun hunAnimationSkipped(entry: NotificationEntry, reason: String) {
buffer.log(TAG, INFO, {
@@ -77,6 +81,79 @@
"isTouchBelowNotification: $bool2 motionEvent: $str1"
})
}
+
+ fun transientNotificationRowTraversalCleaned(entry: NotificationEntry, reason: String) {
+ notificationRenderBuffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ str2 = reason
+ }, {
+ "transientNotificationRowTraversalCleaned: key: $str1 reason: $str2"
+ })
+ }
+
+ fun addTransientChildNotificationToChildContainer(
+ childEntry: NotificationEntry,
+ containerEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(TAG, INFO, {
+ str1 = childEntry.logKey
+ str2 = containerEntry.logKey
+ }, {
+ "addTransientChildToContainer from onViewRemovedInternal: childKey: $str1 " +
+ "-- containerKey: $str2"
+ })
+ }
+
+ fun addTransientChildNotificationToNssl(
+ childEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(TAG, INFO, {
+ str1 = childEntry.logKey
+ }, {
+ "addTransientRowToNssl from onViewRemovedInternal: childKey: $str1"
+ })
+ }
+
+ fun addTransientChildNotificationToViewGroup(
+ childEntry: NotificationEntry,
+ container: ViewGroup
+ ) {
+ notificationRenderBuffer.log(TAG, ERROR, {
+ str1 = childEntry.logKey
+ str2 = container.toString()
+ }, {
+ "addTransientRowTo unhandled ViewGroup from onViewRemovedInternal: childKey: $str1 " +
+ "-- ViewGroup: $str2"
+ })
+ }
+
+ fun addTransientRow(
+ childEntry: NotificationEntry,
+ index: Int
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = childEntry.logKey
+ int1 = index
+ },
+ { "addTransientRow to NSSL: childKey: $str1 -- index: $int1" }
+ )
+ }
+
+ fun removeTransientRow(
+ childEntry: NotificationEntry,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = childEntry.logKey
+ },
+ { "removeTransientRow from NSSL: childKey: $str1" }
+ )
+ }
}
private const val TAG = "NotificationStackScroll"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index fc213b6..b2d26d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -766,8 +766,9 @@
boolean isTopEntry = topHeadsUpEntry == row;
float unmodifiedEndLocation = childState.getYTranslation() + childState.height;
if (mIsExpanded) {
- if (row.mustStayOnScreen() && !childState.headsUpIsVisible
- && !row.showingPulsing() && !ambientState.isOnKeyguard()) {
+ if (shouldHunBeVisibleWhenScrolled(row.mustStayOnScreen(),
+ childState.headsUpIsVisible, row.showingPulsing(),
+ ambientState.isOnKeyguard(), row.getEntry().isStickyAndNotDemoted())) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(mQuickQsOffsetHeight, ambientState.getStackTranslation(),
row.getCollapsedHeight(), childState);
@@ -815,7 +816,15 @@
}
}
- /**
+ @VisibleForTesting
+ boolean shouldHunBeVisibleWhenScrolled(boolean mustStayOnScreen, boolean headsUpIsVisible,
+ boolean showingPulsing, boolean isOnKeyguard, boolean headsUpOnKeyguard) {
+ return mustStayOnScreen && !headsUpIsVisible
+ && !showingPulsing
+ && (!isOnKeyguard || headsUpOnKeyguard);
+ }
+
+ /**
* When shade is open and we are scrolled to the bottom of notifications,
* clamp incoming HUN in its collapsed form, right below qs offset.
* Transition pinned collapsed HUN to full height when scrolling back up.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index f07dd00..d73919b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -347,10 +347,12 @@
final ExpandableView changingView = (ExpandableView) event.mChangingView;
boolean loggable = false;
boolean isHeadsUp = false;
+ boolean isGroupChild = false;
String key = null;
if (changingView instanceof ExpandableNotificationRow && mLogger != null) {
loggable = true;
isHeadsUp = ((ExpandableNotificationRow) changingView).isHeadsUp();
+ isGroupChild = changingView.isChildInGroup();
key = ((ExpandableNotificationRow) changingView).getEntry().getKey();
}
if (event.animationType ==
@@ -407,13 +409,21 @@
}
Runnable postAnimation = changingView::removeFromTransientContainer;
- if (loggable && isHeadsUp) {
- mLogger.logHUNViewDisappearingWithRemoveEvent(key);
+ if (loggable) {
String finalKey = key;
- postAnimation = () -> {
- mLogger.disappearAnimationEnded(finalKey);
- changingView.removeFromTransientContainer();
- };
+ if (isHeadsUp) {
+ mLogger.logHUNViewDisappearingWithRemoveEvent(key);
+ postAnimation = () -> {
+ mLogger.disappearAnimationEnded(finalKey);
+ changingView.removeFromTransientContainer();
+ };
+ } else if (isGroupChild) {
+ mLogger.groupChildRemovalEventProcessed(key);
+ postAnimation = () -> {
+ mLogger.groupChildRemovalAnimationEnded(finalKey);
+ changingView.removeFromTransientContainer();
+ };
+ }
}
changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
0 /* delay */, translationDirection, false /* isHeadsUpAppear */,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index cca84b3..c7f80f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -3,11 +3,13 @@
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
class StackStateLogger @Inject constructor(
- @NotificationHeadsUpLog private val buffer: LogBuffer
+ @NotificationHeadsUpLog private val buffer: LogBuffer,
+ @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
) {
fun logHUNViewDisappearing(key: String) {
buffer.log(TAG, LogLevel.INFO, {
@@ -56,6 +58,21 @@
"Heads up notification appear animation ended $str1 "
})
}
+
+ fun groupChildRemovalEventProcessed(key: String) {
+ notificationRenderBuffer.log(TAG, LogLevel.DEBUG, {
+ str1 = logKey(key)
+ }, {
+ "Group Child Notification removal event processed $str1 for ANIMATION_TYPE_REMOVE"
+ })
+ }
+ fun groupChildRemovalAnimationEnded(key: String) {
+ notificationRenderBuffer.log(TAG, LogLevel.INFO, {
+ str1 = logKey(key)
+ }, {
+ "Group child notification removal animation ended $str1 "
+ })
+ }
}
private const val TAG = "StackScroll"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index aab1c2b..11f68e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
@@ -33,6 +34,7 @@
object NotificationListViewModelModule {
@JvmStatic
@Provides
+ @SysUISingleton
fun maybeProvideViewModel(
featureFlags: FeatureFlags,
shelfViewModel: Provider<NotificationShelfViewModel>,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 18d8050..0242e91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -24,7 +24,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.PowerManager;
import android.os.UserHandle;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -43,7 +42,6 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -196,14 +194,6 @@
@Override
Lifecycle getLifecycle();
- /**
- * Wakes up the device if the device was dozing.
- *
- * @deprecated Use {@link PowerInteractor#wakeUpIfDozing(String, int)} instead.
- */
- @Deprecated
- void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason);
-
/** */
ShadeViewController getShadeViewController();
@@ -212,8 +202,6 @@
int getStatusBarHeight();
- void updateQsExpansionEnabled();
-
boolean isShadeDisabled();
boolean isLaunchingActivityOverLockscreen();
@@ -302,8 +290,6 @@
/** Should the keyguard be hidden immediately in response to a back press/gesture. */
boolean shouldKeyguardHideImmediately();
- boolean onBackPressed();
-
boolean onSpacePressed();
void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
@@ -320,8 +306,6 @@
void setBouncerShowing(boolean bouncerShowing);
- void setBouncerShowingOverDream(boolean bouncerShowingOverDream);
-
int getWakefulnessState();
boolean isScreenFullyOff();
@@ -410,9 +394,6 @@
void setLaunchEmergencyActionOnFinishedWaking(boolean launch);
QSPanelController getQSPanelController();
-
- boolean areNotificationAlertsDisabled();
-
float getDisplayDensity();
void extendDozePulse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 5e0cfd6..332be2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -244,8 +244,13 @@
}
/**
* State is one or more of the DISABLE constants from StatusBarManager.
+ *
+ * @deprecated If you need to react to changes in disable flags, listen to
+ * {@link com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository}
+ * instead.
*/
@Override
+ @Deprecated
public void disable(int displayId, int state1, int state2, boolean animate) {
if (displayId != mDisplayId) {
return;
@@ -255,8 +260,6 @@
state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
Log.d(CentralSurfaces.TAG,
mDisableFlagsLogger.getDisableFlagsString(
- /* old= */ new DisableFlagsLogger.DisableState(
- mCentralSurfaces.getDisabled1(), mCentralSurfaces.getDisabled2()),
/* new= */ new DisableFlagsLogger.DisableState(
state1, state2BeforeAdjustment),
/* newStateAfterLocalModification= */ new DisableFlagsLogger.DisableState(
@@ -277,17 +280,12 @@
}
if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- if (mCentralSurfaces.areNotificationAlertsDisabled()) {
+ if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
mHeadsUpManager.releaseAllImmediately();
}
}
- if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
- mCentralSurfaces.updateQsExpansionEnabled();
- }
-
if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- mCentralSurfaces.updateQsExpansionEnabled();
if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
mShadeController.animateCollapseShade();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 50e286f..4ae4c52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -135,6 +135,7 @@
import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.back.domain.interactor.BackActionInteractor;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -173,6 +174,7 @@
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
@@ -310,7 +312,7 @@
private final DeviceStateManager mDeviceStateManager;
private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
private float mTransitionToFullShadeProgress = 0f;
- private NotificationListContainer mNotifListContainer;
+ private final NotificationListContainer mNotifListContainer;
private boolean mIsShortcutListSearchEnabled;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
@@ -455,6 +457,13 @@
*/
private boolean mShouldDelayWakeUpAnimation = false;
+ /**
+ * Whether we should delay the AOD->Lockscreen animation.
+ * If false, the animation will start in onStartedWakingUp().
+ * If true, the animation will start in onFinishedWakingUp().
+ */
+ private boolean mShouldDelayLockscreenTransitionFromAod = false;
+
private final Object mQueueLock = new Object();
private final PulseExpansionHandler mPulseExpansionHandler;
@@ -599,6 +608,7 @@
private final ViewMediatorCallback mKeyguardViewMediatorCallback;
private final ScrimController mScrimController;
protected DozeScrimController mDozeScrimController;
+ private final BackActionInteractor mBackActionInteractor;
private final Executor mUiBgExecutor;
protected boolean mDozing;
@@ -634,6 +644,7 @@
private final SysuiColorExtractor mColorExtractor;
private final ScreenLifecycle mScreenLifecycle;
private final WakefulnessLifecycle mWakefulnessLifecycle;
+ protected final PowerInteractor mPowerInteractor;
private boolean mNoAnimationOnNextBarModeChange;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -649,8 +660,7 @@
private final ActivityIntentHelper mActivityIntentHelper;
- @VisibleForTesting
- protected NotificationStackScrollLayoutController mStackScrollerController;
+ private final NotificationStackScrollLayoutController mStackScrollerController;
private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
(extractor, which) -> updateTheme();
@@ -658,17 +668,7 @@
private final InteractionJankMonitor mJankMonitor;
/** Existing callback that handles back gesture invoked for the Shade. */
- private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
- if (DEBUG) {
- Log.d(TAG, "mOnBackInvokedCallback() called");
- }
- onBackPressed();
- };
-
- private boolean shouldBackBeHandled() {
- return (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
- && !isBouncerShowingOverDream());
- }
+ private final OnBackInvokedCallback mOnBackInvokedCallback;
/**
* New callback that handles back gesture invoked, cancel, progress
@@ -678,12 +678,12 @@
private final OnBackAnimationCallback mOnBackAnimationCallback = new OnBackAnimationCallback() {
@Override
public void onBackInvoked() {
- onBackPressed();
+ mBackActionInteractor.onBackRequested();
}
@Override
public void onBackProgressed(BackEvent event) {
- if (shouldBackBeHandled()) {
+ if (mBackActionInteractor.shouldBackBeHandled()) {
if (mShadeSurface.canBeCollapsed()) {
float fraction = event.getProgress();
mShadeSurface.onBackProgressed(fraction);
@@ -737,6 +737,7 @@
SysuiColorExtractor colorExtractor,
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
+ PowerInteractor powerInteractor,
SysuiStatusBarStateController statusBarStateController,
Optional<Bubbles> bubblesOptional,
Lazy<NoteTaskController> noteTaskControllerLazy,
@@ -747,12 +748,14 @@
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
NotificationShelfController notificationShelfController,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController,
DozeParameters dozeParameters,
ScrimController scrimController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
AuthRippleController authRippleController,
DozeServiceHost dozeServiceHost,
+ BackActionInteractor backActionInteractor,
PowerManager powerManager,
ScreenPinningRequest screenPinningRequest,
DozeScrimController dozeScrimController,
@@ -812,6 +815,7 @@
mKeyguardBypassController = keyguardBypassController;
mKeyguardStateController = keyguardStateController;
mHeadsUpManager = headsUpManagerPhone;
+ mBackActionInteractor = backActionInteractor;
mKeyguardIndicationController = keyguardIndicationController;
mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
mFalsingCollector = falsingCollector;
@@ -834,6 +838,7 @@
mColorExtractor = colorExtractor;
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
+ mPowerInteractor = powerInteractor;
mStatusBarStateController = statusBarStateController;
mBubblesOptional = bubblesOptional;
mNoteTaskControllerLazy = noteTaskControllerLazy;
@@ -844,6 +849,9 @@
mConfigurationController = configurationController;
mNotificationShadeWindowController = notificationShadeWindowController;
mNotificationShelfController = notificationShelfController;
+ mStackScrollerController = notificationStackScrollLayoutController;
+ mStackScroller = mStackScrollerController.getView();
+ mNotifListContainer = mStackScrollerController.getNotificationListContainer();
mDozeServiceHost = dozeServiceHost;
mPowerManager = powerManager;
mDozeParameters = dozeParameters;
@@ -931,6 +939,12 @@
}
// Based on teamfood flag, enable predictive back animation for the Shade.
mAnimateBack = mFeatureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE);
+ mOnBackInvokedCallback = () -> {
+ if (DEBUG) {
+ Log.d(TAG, "mOnBackInvokedCallback() called");
+ }
+ mBackActionInteractor.onBackRequested();
+ };
}
private void initBubbles(Bubbles bubbles) {
@@ -1571,7 +1585,6 @@
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
mShadeController.setNotificationPresenter(mPresenter);
mNotificationsController.initialize(
- this,
mPresenter,
mNotifListContainer,
mStackScrollerController.getNotifStackController(),
@@ -1587,24 +1600,6 @@
mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */);
}
- /**
- * Ask the display to wake up if currently dozing, else do nothing
- *
- * @deprecated Use {@link PowerInteractor#wakeUpIfDozing(String, int)} instead.
- *
- * @param time when to wake up
- * @param why the reason for the wake up
- */
- @Override
- @Deprecated
- public void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason) {
- if (mDozing && mScreenOffAnimationController.allowWakeUpIfDozing()) {
- mPowerManager.wakeUp(
- time, wakeReason, "com.android.systemui:" + why);
- mFalsingCollector.onScreenOnFromTouch();
- }
- }
-
// TODO(b/117478341): This was left such that CarStatusBar can override this method.
// Try to remove this.
protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
@@ -1647,11 +1642,8 @@
mShadeController.setNotificationPanelViewController(npvc);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
- mStackScrollerController =
- mCentralSurfacesComponent.getNotificationStackScrollLayoutController();
mQsController = mCentralSurfacesComponent.getQuickSettingsController();
- mStackScroller = mStackScrollerController.getView();
- mNotifListContainer = mCentralSurfacesComponent.getNotificationListContainer();
+ mBackActionInteractor.setup(mQsController, mShadeSurface);
mPresenter = mCentralSurfacesComponent.getNotificationPresenter();
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
@@ -1732,23 +1724,6 @@
return mStatusBarWindowController.getStatusBarHeight();
}
- /**
- * Disable QS if device not provisioned.
- * If the user switcher is simple then disable QS during setup because
- * the user intends to use the lock screen user switcher, QS in not needed.
- */
- @Override
- public void updateQsExpansionEnabled() {
- final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
- && (mUserSetup || mUserSwitcherController == null
- || !mUserSwitcherController.isSimpleUserSwitcher())
- && !isShadeDisabled()
- && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
- && !mDozing;
- mQsController.setExpansionEnabledPolicy(expandEnabled);
- Log.d(TAG, "updateQsExpansionEnabled - QS Expand enabled: " + expandEnabled);
- }
-
@Override
public boolean isShadeDisabled() {
return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
@@ -1762,11 +1737,6 @@
&& mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
}
- @Override
- public boolean areNotificationAlertsDisabled() {
- return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
- }
-
/**
* Whether we are currently animating an activity launch above the lockscreen (occluding
* activity).
@@ -2716,7 +2686,6 @@
|| (mDozing && mDozeParameters.shouldControlScreenOff() && keyguardVisibleOrWillBe);
mShadeSurface.setDozing(mDozing, animate);
- updateQsExpansionEnabled();
Trace.endSection();
}
@@ -2745,7 +2714,7 @@
case KeyEvent.KEYCODE_BACK:
if (mState == StatusBarState.KEYGUARD
&& mStatusBarKeyguardViewManager.dispatchBackKeyEventPreIme()) {
- return onBackPressed();
+ return mBackActionInteractor.onBackRequested();
}
}
return false;
@@ -2785,34 +2754,6 @@
}
@Override
- public boolean onBackPressed() {
- if (mStatusBarKeyguardViewManager.canHandleBackPressed()) {
- mStatusBarKeyguardViewManager.onBackPressed();
- return true;
- }
- if (mQsController.isCustomizing()) {
- mQsController.closeQsCustomizer();
- return true;
- }
- if (mQsController.getExpanded()) {
- mShadeSurface.animateCollapseQs(false);
- return true;
- }
- if (mShadeSurface.closeUserSwitcherIfOpen()) {
- return true;
- }
- if (shouldBackBeHandled()) {
- if (mShadeSurface.canBeCollapsed()) {
- // this is the Shade dismiss animation, so make sure QQS closes when it ends.
- mShadeSurface.onBackPressed();
- mShadeController.animateCollapseShade();
- }
- return true;
- }
- return false;
- }
-
- @Override
public boolean onSpacePressed() {
if (mDeviceInteractive && mState != StatusBarState.SHADE) {
mShadeController.animateCollapseShadeForced();
@@ -2929,8 +2870,7 @@
mStatusBarHideIconsForBouncerManager.setBouncerShowingAndTriggerUpdate(bouncerShowing);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
if (mBouncerShowing) {
- wakeUpIfDozing(SystemClock.uptimeMillis(), "BOUNCER_VISIBLE",
- PowerManager.WAKE_REASON_GESTURE);
+ mPowerInteractor.wakeUpIfDozing("BOUNCER_VISIBLE", PowerManager.WAKE_REASON_GESTURE);
}
updateScrimController();
if (!mBouncerShowing) {
@@ -2939,17 +2879,6 @@
}
/**
- * Sets whether the bouncer over dream is showing. Note that the bouncer over dream is handled
- * independently of the rest of the notification panel. As a result, setting this state via
- * {@link #setBouncerShowing(boolean)} leads to unintended side effects from states modified
- * behind the dream.
- */
- @Override
- public void setBouncerShowingOverDream(boolean bouncerShowingOverDream) {
- mBouncerShowingOverDream = bouncerShowingOverDream;
- }
-
- /**
* Propagate the bouncer state to status bar components.
*
* Separate from {@link #setBouncerShowing} because we sometimes re-create the status bar and
@@ -3073,28 +3002,43 @@
updateVisibleToUser();
updateIsKeyguard();
+ mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn()
+ && mFeatureFlags.isEnabled(
+ Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD);
+ if (!mShouldDelayLockscreenTransitionFromAod) {
+ startLockscreenTransitionFromAod();
+ }
});
DejankUtils.stopDetectingBlockingIpcs(tag);
}
+ /**
+ * Private helper for starting the LOCKSCREEN_TRANSITION_FROM_AOD animation - only necessary
+ * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp().
+ */
+ private void startLockscreenTransitionFromAod() {
+ // stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation.
+ mDozeServiceHost.stopDozing();
+ // This is intentionally below the stopDozing call above, since it avoids that we're
+ // unnecessarily animating the wakeUp transition. Animations should only be enabled
+ // once we fully woke up.
+ updateRevealEffect(true /* wakingUp */);
+ updateNotificationPanelTouchState();
+ mStatusBarTouchableRegionManager.updateTouchableRegion();
+
+ // If we are waking up during the screen off animation, we should undo making the
+ // expanded visible (we did that so the LightRevealScrim would be visible).
+ if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) {
+ mShadeController.makeExpandedInvisible();
+ }
+ }
+
@Override
public void onFinishedWakingUp() {
- mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
- // stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation.
- mDozeServiceHost.stopDozing();
- // This is intentionally below the stopDozing call above, since it avoids that we're
- // unnecessarily animating the wakeUp transition. Animations should only be enabled
- // once we fully woke up.
- updateRevealEffect(true /* wakingUp */);
- updateNotificationPanelTouchState();
- mStatusBarTouchableRegionManager.updateTouchableRegion();
-
- // If we are waking up during the screen off animation, we should undo making the
- // expanded visible (we did that so the LightRevealScrim would be visible).
- if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) {
- mShadeController.makeExpandedInvisible();
- }
- });
+ if (mShouldDelayLockscreenTransitionFromAod) {
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(
+ this::startLockscreenTransitionFromAod);
+ }
mWakeUpCoordinator.setFullyAwake(true);
mWakeUpCoordinator.setWakingUp(false, false);
if (mKeyguardStateController.isOccluded()
@@ -3381,7 +3325,7 @@
protected IStatusBarService mBarService;
// all notifications
- protected NotificationStackScrollLayout mStackScroller;
+ private final NotificationStackScrollLayout mStackScroller;
protected AccessibilityManager mAccessibilityManager;
@@ -3648,7 +3592,6 @@
mShadeSurface.collapse(true /* animate */, false /* delayed */,
1.0f /* speedUpFactor */);
}
- updateQsExpansionEnabled();
}
}
};
@@ -3783,7 +3726,6 @@
// reset them again when we're waking up
mShadeSurface.resetViews(dozingAnimated && isDozing);
- updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
updateDozingState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 61c1cc8..29a249f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -51,6 +51,7 @@
private KeyguardIndication mKeyguardIndicationInfo;
private Animator mLastAnimator;
+ private boolean mAlwaysAnnounceText;
public KeyguardIndicationTextView(Context context) {
super(context);
@@ -104,6 +105,19 @@
}
/**
+ * Controls whether the text displayed in the indication area will be announced always.
+ */
+ public void setAlwaysAnnounceEnabled(boolean enabled) {
+ this.mAlwaysAnnounceText = enabled;
+ if (mAlwaysAnnounceText) {
+ // We will announce the text programmatically anyway.
+ setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_NONE);
+ } else {
+ setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
+ }
+ }
+
+ /**
* Updates the text with an optional animation.
*
* @param text The text to show.
@@ -227,6 +241,9 @@
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
}
setText(mMessage);
+ if (mAlwaysAnnounceText) {
+ announceForAccessibility(mMessage);
+ }
}
private AnimatorSet getInAnimator() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 7bc4fc3..ae70384 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -115,7 +115,6 @@
};
private final Context mContext;
- private Boolean mOverrideIconTintForNavMode;
@AssistedInject
public LightBarTransitionsController(
@@ -276,19 +275,11 @@
}
/**
- * Specify an override value to return for {@link #overrideIconTintForNavMode(boolean)}.
- */
- public void overrideIconTintForNavMode(boolean overrideValue) {
- mOverrideIconTintForNavMode = overrideValue;
- }
- /**
* Return whether to use the tint calculated in this class for nav icons.
*/
public boolean supportsIconTintForNavMode(int navigationMode) {
// In gesture mode, we already do region sampling to update tint based on content beneath.
- return mOverrideIconTintForNavMode != null
- ? mOverrideIconTintForNavMode
- : !QuickStepContract.isGesturalMode(navigationMode);
+ return !QuickStepContract.isGesturalMode(navigationMode);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index bb4aacb..e63875b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -53,16 +53,16 @@
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.ui.BouncerView;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.bouncer.ui.BouncerView;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
@@ -144,6 +144,7 @@
// Local cache of expansion events, to avoid duplicates
private float mFraction = -1f;
private boolean mTracking = false;
+ private boolean mBouncerShowingOverDream;
private final PrimaryBouncerExpansionCallback mExpansionCallback =
new PrimaryBouncerExpansionCallback() {
@@ -182,8 +183,8 @@
@Override
public void onVisibilityChanged(boolean isVisible) {
- mCentralSurfaces.setBouncerShowingOverDream(
- isVisible && mDreamOverlayStateController.isOverlayActive());
+ mBouncerShowingOverDream =
+ isVisible && mDreamOverlayStateController.isOverlayActive();
if (!isVisible) {
mCentralSurfaces.setPrimaryBouncerHiddenFraction(EXPANSION_HIDDEN);
@@ -823,6 +824,11 @@
}
@Override
+ public boolean isBouncerShowingOverDream() {
+ return mBouncerShowingOverDream;
+ }
+
+ @Override
public void setOccluded(boolean occluded, boolean animate) {
final boolean wasOccluded = mKeyguardStateController.isOccluded();
final boolean isOccluding = !wasOccluded && occluded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 3b56d27..35285b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -22,7 +22,6 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -36,6 +35,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeViewController;
@@ -53,6 +53,7 @@
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -83,7 +84,9 @@
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
private final CentralSurfaces mCentralSurfaces;
+ private final NotificationsInteractor mNotificationsInteractor;
private final LockscreenShadeTransitionController mShadeTransitionController;
+ private final PowerInteractor mPowerInteractor;
private final CommandQueue mCommandQueue;
private final AccessibilityManager mAccessibilityManager;
@@ -111,7 +114,9 @@
DynamicPrivacyController dynamicPrivacyController,
KeyguardStateController keyguardStateController,
CentralSurfaces centralSurfaces,
+ NotificationsInteractor notificationsInteractor,
LockscreenShadeTransitionController shadeTransitionController,
+ PowerInteractor powerInteractor,
CommandQueue commandQueue,
NotificationLockscreenUserManager lockscreenUserManager,
SysuiStatusBarStateController sysuiStatusBarStateController,
@@ -133,7 +138,9 @@
mDynamicPrivacyController = dynamicPrivacyController;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mCentralSurfaces = centralSurfaces;
+ mNotificationsInteractor = notificationsInteractor;
mShadeTransitionController = shadeTransitionController;
+ mPowerInteractor = powerInteractor;
mCommandQueue = commandQueue;
mLockscreenUserManager = lockscreenUserManager;
mStatusBarStateController = sysuiStatusBarStateController;
@@ -234,9 +241,7 @@
public void onExpandClicked(NotificationEntry clickedEntry, View clickedView,
boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
- mCentralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
- PowerManager.WAKE_REASON_GESTURE);
+ mPowerInteractor.wakeUpIfDozing("NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE);
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
@@ -333,7 +338,7 @@
@Override
public boolean suppressInterruptions(NotificationEntry entry) {
- return mCentralSurfaces.areNotificationAlertsDisabled();
+ return !mNotificationsInteractor.areNotificationAlertsEnabled();
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index 64c798b..c618be8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -28,9 +28,6 @@
import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule;
import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks;
import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
@@ -56,7 +53,6 @@
* outside the component. Should more items be moved *into* this component to avoid so many getters?
*/
@Subcomponent(modules = {
- NotificationStackScrollLayoutListContainerModule.class,
StatusBarViewModule.class,
StatusBarNotificationActivityStarterModule.class,
StatusBarNotificationPresenterModule.class,
@@ -87,9 +83,6 @@
*/
NotificationShadeWindowView getNotificationShadeWindowView();
- /** */
- NotificationStackScrollLayoutController getNotificationStackScrollLayoutController();
-
/**
* Creates a NotificationShadeWindowViewController.
*/
@@ -128,6 +121,4 @@
NotificationActivityStarter getNotificationActivityStarter();
NotificationPresenter getNotificationPresenter();
-
- NotificationListContainer getNotificationListContainer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 260d986..6b0746f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -31,8 +31,6 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
@@ -60,11 +58,14 @@
import javax.inject.Named;
-@Module(subcomponents = StatusBarFragmentComponent.class,
- includes = {
- ActivatableNotificationViewModelModule.class,
- NotificationListViewModelModule.class,
- })
+/**
+ * A module for {@link CentralSurfacesComponent.CentralSurfacesScope} components.
+ *
+ * @deprecated CentralSurfacesScope will be removed shortly (b/277762009). Classes should be
+ * annotated with @SysUISingleton instead.
+ */
+@Module(subcomponents = StatusBarFragmentComponent.class)
+@Deprecated
public abstract class StatusBarViewModule {
public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index 8c19fb4..f4ab408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -33,7 +33,6 @@
* modifications that were made to the flags locally.
*
* @param new see [DisableFlagsLogger.getDisableFlagsString]
- * @param newAfterLocalModification see [DisableFlagsLogger.getDisableFlagsString]
*/
fun logDisableFlagChange(
new: DisableFlagsLogger.DisableState,
@@ -47,8 +46,7 @@
},
{
disableFlagsLogger.getDisableFlagsString(
- old = null,
- new = DisableFlagsLogger.DisableState(int1, int2),
+ DisableFlagsLogger.DisableState(int1, int2),
)
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 2b4f51c..4c6374b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -35,7 +35,10 @@
) : BaseAdapter() {
protected open val users: List<UserRecord>
- get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
+ get() = controller.users.filter {
+ (!controller.isKeyguardShowing || !it.isRestricted) &&
+ (controller.isUserSwitcherEnabled || it.isCurrent)
+ }
init {
controller.addAdapter(WeakReference(this))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
index 1e223b1..f88339a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
@@ -67,6 +67,9 @@
val isSimpleUserSwitcher: Boolean
get() = userInteractor.isSimpleUserSwitcher
+ val isUserSwitcherEnabled: Boolean
+ get() = userInteractor.isUserSwitcherEnabled
+
/** The [UserRecord] of the current user or `null` when none. */
val currentUserRecord: UserRecord?
get() = userInteractor.selectedUserRecord.value
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index a0b56aa..3de75ca 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -105,6 +105,8 @@
fun getSelectedUserInfo(): UserInfo
fun isSimpleUserSwitcher(): Boolean
+
+ fun isUserSwitcherEnabled(): Boolean
}
@SysUISingleton
@@ -206,6 +208,10 @@
return _userSwitcherSettings.value.isSimpleUserSwitcher
}
+ override fun isUserSwitcherEnabled(): Boolean {
+ return _userSwitcherSettings.value.isUserSwitcherEnabled
+ }
+
private fun observeUserSwitching() {
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 27c348b..a487f53 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -294,6 +294,10 @@
val isSimpleUserSwitcher: Boolean
get() = repository.isSimpleUserSwitcher()
+
+ val isUserSwitcherEnabled: Boolean
+ get() = repository.isUserSwitcherEnabled()
+
val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
override fun onKeyguardGoingAway() {
@@ -370,6 +374,7 @@
}
pw.println("isSimpleUserSwitcher=$isSimpleUserSwitcher")
+ pw.println("isUserSwitcherEnabled=$isUserSwitcherEnabled")
pw.println("isGuestUserAutoCreated=$isGuestUserAutoCreated")
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index d6b3b22..12d7b4d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -19,12 +19,44 @@
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.lifecycle.repeatWhenAttached
import java.util.function.Consumer
+import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+/** A class allowing Java classes to collect on Kotlin flows. */
+@SysUISingleton
+class JavaAdapter
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+) {
+ /**
+ * Collect information for the given [flow], calling [consumer] for each emitted event.
+ *
+ * Important: This will immediately start collection and *never* stop it. This should only be
+ * used by classes that *need* to always be collecting a value and processing it. Whenever
+ * possible, please use [collectFlow] instead; that method will stop the collection when a view
+ * has disappeared, which will ensure that we don't perform unnecessary work.
+ *
+ * Do *not* call this method in a class's constructor. Instead, call it in
+ * [com.android.systemui.CoreStartable.start] or similar method.
+ */
+ fun <T> alwaysCollectFlow(
+ flow: Flow<T>,
+ consumer: Consumer<T>,
+ ): Job {
+ return scope.launch { flow.collect { consumer.accept(it) } }
+ }
+}
/**
* Collect information for the given [flow], calling [consumer] for each emitted event. Defaults to
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f37a9b5..7456d34 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -928,7 +928,6 @@
showRingerDrawer();
}
});
- updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
mRingerDrawerVibrate.setOnClickListener(
new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE));
@@ -991,19 +990,6 @@
: 0;
}
- @VisibleForTesting String getSelectedRingerContainerDescription() {
- return mSelectedRingerContainer == null ? null :
- mSelectedRingerContainer.getContentDescription().toString();
- }
-
- @VisibleForTesting void toggleRingerDrawer(boolean show) {
- if (show) {
- showRingerDrawer();
- } else {
- hideRingerDrawer();
- }
- }
-
/** Animates in the ringer drawer. */
private void showRingerDrawer() {
if (mIsRingerDrawerOpen) {
@@ -1081,7 +1067,12 @@
.start();
}
- updateSelectedRingerContainerDescription(true);
+ // When the ringer drawer is open, tapping the currently selected ringer will set the ringer
+ // to the current ringer mode. Change the content description to that, instead of the 'tap
+ // to change ringer mode' default.
+ mSelectedRingerContainer.setContentDescription(
+ mContext.getString(getStringDescriptionResourceForRingerMode(
+ mState.ringerModeInternal)));
mIsRingerDrawerOpen = true;
}
@@ -1127,38 +1118,14 @@
.translationY(0f)
.start();
- updateSelectedRingerContainerDescription(false);
+ // When the drawer is closed, tapping the selected ringer drawer will open it, allowing the
+ // user to change the ringer.
+ mSelectedRingerContainer.setContentDescription(
+ mContext.getString(R.string.volume_ringer_change));
mIsRingerDrawerOpen = false;
}
-
- /**
- * @param open false to set the description when drawer is closed
- */
- private void updateSelectedRingerContainerDescription(boolean open) {
- if (mState == null || mSelectedRingerContainer == null) return;
-
- String currentMode = mContext.getString(getStringDescriptionResourceForRingerMode(
- mState.ringerModeInternal));
- String tapToSelect;
-
- if (open) {
- // When the ringer drawer is open, tapping the currently selected ringer will set the
- // ringer to the current ringer mode. Change the content description to that, instead of
- // the 'tap to change ringer mode' default.
- tapToSelect = "";
-
- } else {
- // When the drawer is closed, tapping the selected ringer drawer will open it, allowing
- // the user to change the ringer. The user needs to know that, and also the current mode
- currentMode += ", ";
- tapToSelect = mContext.getString(R.string.volume_ringer_change);
- }
-
- mSelectedRingerContainer.setContentDescription(currentMode + tapToSelect);
- }
-
private void initSettingsH(int lockTaskModeState) {
if (mSettingsView != null) {
mSettingsView.setVisibility(
@@ -1734,7 +1701,7 @@
});
}
- @VisibleForTesting int getStringDescriptionResourceForRingerMode(int mode) {
+ private int getStringDescriptionResourceForRingerMode(int mode) {
switch (mode) {
case RINGER_MODE_SILENT:
return R.string.volume_ringer_status_silent;
@@ -1816,7 +1783,6 @@
updateVolumeRowH(row);
}
updateRingerH();
- updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
mWindow.setTitle(composeWindowTitle());
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 5144d19..4c7e6b0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -334,8 +334,10 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis,
- int backDisposition, boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
+ boolean showImeSwitcher) {
if (displayId == mDisplayTracker.getDefaultDisplayId()
&& (vis & InputMethodService.IME_VISIBLE) != 0) {
oneHanded.stopOneHanded(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index 48a8d1b..e7d420b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -561,6 +561,66 @@
captor.getValue().carrierText);
}
+ @Test
+ public void testGetStatusForIccState() {
+ when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
+ assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+ assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+ assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_NOT_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PIN_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PUK_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.Normal,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PERM_DISABLED));
+ assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+ assertEquals(CarrierTextManager.StatusMode.SimIoError,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+ assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+
+ when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ assertEquals(CarrierTextManager.StatusMode.SimMissing,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+ assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+ assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NOT_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PIN_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PUK_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.Normal,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimPermDisabled,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PERM_DISABLED));
+ assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+ assertEquals(CarrierTextManager.StatusMode.SimIoError,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+ assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+ }
+
private Context getContextSpyForStickyBroadcast(Intent returnVal) {
Context contextSpy = spy(mContext);
doReturn(returnVal).when(contextSpy).registerReceiver(eq(null), any(IntentFilter.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index ae3a320..fa32835 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.KeyEvent;
@@ -183,4 +184,15 @@
mKeyguardAbsKeyInputViewController.onResume(KeyguardSecurityView.VIEW_REVEALED);
verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt());
}
+
+ @Test
+ public void testLockedOut_verifyPasswordAndUnlock_doesNotEnableViewInput() {
+ mKeyguardAbsKeyInputViewController.handleAttemptLockout(
+ SystemClock.elapsedRealtime() + 1000);
+ mKeyguardAbsKeyInputViewController.verifyPasswordAndUnlock();
+ verify(mAbsKeyInputView).setPasswordEntryInputEnabled(false);
+ verify(mAbsKeyInputView).setPasswordEntryEnabled(false);
+ verify(mAbsKeyInputView, never()).setPasswordEntryInputEnabled(true);
+ verify(mAbsKeyInputView, never()).setPasswordEntryEnabled(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 71a57c7..2eea9eb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -18,10 +18,12 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.internal.widget.LockPatternUtils
-import com.android.internal.widget.LockPatternView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
@@ -29,6 +31,10 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,7 +51,7 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardPatternViewControllerTest : SysuiTestCase() {
- @Mock private lateinit var mKeyguardPatternView: KeyguardPatternView
+ private lateinit var mKeyguardPatternView: KeyguardPatternView
@Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
@@ -63,54 +69,70 @@
@Mock
private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
- @Mock private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
-
@Mock
private lateinit var mKeyguardMessageAreaController:
KeyguardMessageAreaController<BouncerKeyguardMessageArea>
- @Mock private lateinit var mLockPatternView: LockPatternView
-
- @Mock private lateinit var mPostureController: DevicePostureController
+ @Mock private lateinit var mPostureController: DevicePostureController
private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
private lateinit var fakeFeatureFlags: FakeFeatureFlags
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
- `when`(
- mKeyguardPatternView.requireViewById<BouncerKeyguardMessageArea>(
- R.id.bouncer_message_area))
- .thenReturn(mKeyguardMessageArea)
- `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
- .thenReturn(mLockPatternView)
- `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea))
- .thenReturn(mKeyguardMessageAreaController)
- `when`(mKeyguardPatternView.resources).thenReturn(context.resources)
- fakeFeatureFlags = FakeFeatureFlags()
- fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, false)
- mKeyguardPatternViewController =
- KeyguardPatternViewController(
- mKeyguardPatternView,
- mKeyguardUpdateMonitor,
- mSecurityMode,
- mLockPatternUtils,
- mKeyguardSecurityCallback,
- mLatencyTracker,
- mFalsingCollector,
- mEmergencyButtonController,
- mKeyguardMessageAreaControllerFactory,
- mPostureController,
- fakeFeatureFlags)
- }
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ whenever(mKeyguardMessageAreaControllerFactory.create(any()))
+ .thenReturn(mKeyguardMessageAreaController)
+ fakeFeatureFlags = FakeFeatureFlags()
+ fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, false)
+ mKeyguardPatternView = View.inflate(mContext, R.layout.keyguard_pattern_view, null)
+ as KeyguardPatternView
+
+
+ mKeyguardPatternViewController =
+ KeyguardPatternViewController(
+ mKeyguardPatternView,
+ mKeyguardUpdateMonitor,
+ mSecurityMode,
+ mLockPatternUtils,
+ mKeyguardSecurityCallback,
+ mLatencyTracker,
+ mFalsingCollector,
+ mEmergencyButtonController,
+ mKeyguardMessageAreaControllerFactory,
+ mPostureController,
+ fakeFeatureFlags
+ )
+ mKeyguardPatternView.onAttachedToWindow()
+ }
+
+ @Test
+ fun tabletopPostureIsDetectedFromStart() {
+ overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
+ whenever(mPostureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
+
+ mKeyguardPatternViewController.onViewAttached()
+
+ assertThat(getPatternTopGuideline()).isEqualTo(getExpectedTopGuideline())
+ }
+
+ private fun getPatternTopGuideline(): Float {
+ val cs = ConstraintSet()
+ val container =
+ mKeyguardPatternView.findViewById(R.id.pattern_container) as ConstraintLayout
+ cs.clone(container)
+ return cs.getConstraint(R.id.pattern_top_guideline).layout.guidePercent
+ }
+
+ private fun getExpectedTopGuideline(): Float {
+ return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio)
+ }
@Test
fun withFeatureFlagOn_oldMessage_isHidden() {
fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
- mKeyguardPatternViewController.init()
+ mKeyguardPatternViewController.onViewAttached()
verify<KeyguardMessageAreaController<*>>(mKeyguardMessageAreaController).disable()
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 0edfd77..b0576e0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -169,6 +169,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -677,6 +678,130 @@
}
@Test
+ public void testHandleSimStateChange_Unknown() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_UNKNOWN);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_UNKNOWN,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Absent() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_ABSENT);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_ABSENT,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_CardIOError() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_IO_ERROR);
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_IO_ERROR);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_IO_ERROR,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_CardRestricted() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_RESTRICTED);
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_RESTRICTED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_RESTRICTED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Locked() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOCKED);
+
+ // locked on PIN1
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PIN);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PIN_REQUIRED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // locked on PUK1
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PUK);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PUK_REQUIRED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // locked on network personalization
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_NETWORK);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // permanently disabled due to puk fails
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_ABSENT_ON_PERM_DISABLED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PERM_DISABLED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_NotReady() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_NOT_READY);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_NOT_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Ready() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+
+ // ICC IMSI is ready in property
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_IMSI);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // ICC is ready to access
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_READY);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // all ICC records, including IMSI, are loaded
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOADED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
public void testTriesToAuthenticateFingerprint_whenKeyguard() {
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
@@ -3144,6 +3269,7 @@
private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
+ AtomicInteger mCachedSimState = new AtomicInteger(-1);
protected TestableKeyguardUpdateMonitor(Context context) {
super(context, mUserTracker,
@@ -3166,9 +3292,14 @@
return mSimStateChanged.getAndSet(false);
}
+ public int getCachedSimState() {
+ return mCachedSimState.getAndSet(-1);
+ }
+
@Override
protected void handleSimStateChange(int subId, int slotId, int state) {
mSimStateChanged.set(true);
+ mCachedSimState.set(state);
super.handleSimStateChange(subId, slotId, state);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
deleted file mode 100644
index ef3af8a..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
+++ /dev/null
@@ -1,76 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public final class AnalogClockControllerTest extends SysuiTestCase {
-
- private AnalogClockController mClockController;
- @Mock SysuiColorExtractor mMockColorExtractor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- Resources res = getContext().getResources();
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- mClockController = new AnalogClockController(res, layoutInflater,
- mMockColorExtractor);
- }
-
- @Test
- public void setDarkAmount_AOD() {
- ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
- View smallClock = smallClockFrame.getChildAt(0);
- // WHEN dark amount is set to AOD
- mClockController.setDarkAmount(1f);
- // THEN small clock should be shown.
- assertThat(smallClock.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void setColorPalette_setDigitalClock() {
- ViewGroup smallClock = (ViewGroup) mClockController.getView();
- // WHEN color palette is set
- mClockController.setColorPalette(true, new int[]{Color.RED});
- // THEN child of small clock should have text color set.
- TextView digitalClock = (TextView) smallClock.getChildAt(0);
- assertThat(digitalClock.getCurrentTextColor()).isEqualTo(Color.RED);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
deleted file mode 100644
index b56986e..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
+++ /dev/null
@@ -1,75 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public final class BubbleClockControllerTest extends SysuiTestCase {
-
- private BubbleClockController mClockController;
- @Mock SysuiColorExtractor mMockColorExtractor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- Resources res = getContext().getResources();
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- mClockController = new BubbleClockController(res, layoutInflater, mMockColorExtractor);
- }
-
- @Test
- public void setDarkAmount_AOD() {
- ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
- View smallClock = smallClockFrame.getChildAt(0);
- // WHEN dark amount is set to AOD
- mClockController.setDarkAmount(1f);
- // THEN small clock should not be shown.
- assertThat(smallClock.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void setColorPalette_setDigitalClock() {
- ViewGroup smallClock = (ViewGroup) mClockController.getView();
- // WHEN text color is set
- mClockController.setColorPalette(true, new int[]{Color.RED});
- // THEN child of small clock should have text color set.
- TextView digitalClock = (TextView) smallClock.getChildAt(0);
- assertThat(digitalClock.getCurrentTextColor()).isEqualTo(Color.RED);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
deleted file mode 100644
index 4c0890a..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
+++ /dev/null
@@ -1,84 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-
-import android.graphics.Bitmap;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.function.Supplier;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public final class ClockInfoTest extends SysuiTestCase {
-
- @Mock
- private Supplier<Bitmap> mMockSupplier;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testGetName() {
- final String name = "name";
- ClockInfo info = ClockInfo.builder().setName(name).build();
- assertThat(info.getName()).isEqualTo(name);
- }
-
- @Test
- public void testGetTitle() {
- final String title = "title";
- ClockInfo info = ClockInfo.builder().setTitle(() -> title).build();
- assertThat(info.getTitle()).isEqualTo(title);
- }
-
- @Test
- public void testGetId() {
- final String id = "id";
- ClockInfo info = ClockInfo.builder().setId(id).build();
- assertThat(info.getId()).isEqualTo(id);
- }
-
- @Test
- public void testGetThumbnail() {
- ClockInfo info = ClockInfo.builder().setThumbnail(mMockSupplier).build();
- info.getThumbnail();
- verify(mMockSupplier).get();
- }
-
- @Test
- public void testGetPreview() {
- ClockInfo info = ClockInfo.builder().setPreview(mMockSupplier).build();
- info.getPreview();
- verify(mMockSupplier).get();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
deleted file mode 100644
index 7a5b772..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ /dev/null
@@ -1,258 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.LayoutInflater;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dock.DockManagerFake;
-import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-// Need to run tests on main looper to allow for onClockChanged operation to happen synchronously.
-@RunWithLooper(setAsMainLooper = true)
-public final class ClockManagerTest extends SysuiTestCase {
-
- private static final String BUBBLE_CLOCK = BubbleClockController.class.getName();
- private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class;
- private static final int MAIN_USER_ID = 0;
- private static final int SECONDARY_USER_ID = 11;
- private static final Uri SETTINGS_URI = null;
-
- private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
- private ClockManager mClockManager;
- private ContentObserver mContentObserver;
- private DockManagerFake mFakeDockManager;
- private ArgumentCaptor<UserTracker.Callback> mUserTrackerCallbackCaptor;
- @Mock PluginManager mMockPluginManager;
- @Mock SysuiColorExtractor mMockColorExtractor;
- @Mock ContentResolver mMockContentResolver;
- @Mock UserTracker mUserTracker;
- @Mock SettingsWrapper mMockSettingsWrapper;
- @Mock ClockManager.ClockChangedListener mMockListener1;
- @Mock ClockManager.ClockChangedListener mMockListener2;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- LayoutInflater inflater = LayoutInflater.from(getContext());
-
- mFakeDockManager = new DockManagerFake();
-
- when(mUserTracker.getUserId()).thenReturn(MAIN_USER_ID);
- mUserTrackerCallbackCaptor = ArgumentCaptor.forClass(UserTracker.Callback.class);
-
- mClockManager = new ClockManager(getContext(), inflater,
- mMockPluginManager, mMockColorExtractor, mMockContentResolver,
- mUserTracker, mMainExecutor, mMockSettingsWrapper, mFakeDockManager);
-
- mClockManager.addBuiltinClock(() -> new BubbleClockController(
- getContext().getResources(), inflater, mMockColorExtractor));
- mClockManager.addOnClockChangedListener(mMockListener1);
- mClockManager.addOnClockChangedListener(mMockListener2);
- verify(mUserTracker).addCallback(mUserTrackerCallbackCaptor.capture(), any());
- reset(mMockListener1, mMockListener2);
-
- mContentObserver = mClockManager.getContentObserver();
- }
-
- @After
- public void tearDown() {
- mClockManager.removeOnClockChangedListener(mMockListener1);
- mClockManager.removeOnClockChangedListener(mMockListener2);
- }
-
- @Test
- public void dockEvent() {
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- assertThat(mClockManager.isDocked()).isTrue();
- }
-
- @Test
- public void undockEvent() {
- mFakeDockManager.setDockEvent(DockManager.STATE_NONE);
- assertThat(mClockManager.isDocked()).isFalse();
- }
-
- @Test
- public void getCurrentClock_default() {
- // GIVEN that settings doesn't contain any values
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
- when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
- // WHEN settings change event is fired
- mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
- // THEN the result is null, indicated the default clock face should be used.
- assertThat(mClockManager.getCurrentClock()).isNull();
- }
-
- @Test
- public void getCurrentClock_customClock() {
- // GIVEN that settings is set to the bubble clock face
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
- // WHEN settings change event is fired
- mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
- // THEN the plugin is the bubble clock face.
- assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- @Test
- public void onClockChanged_customClock() {
- // GIVEN that settings is set to the bubble clock face
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
- // WHEN settings change event is fired
- mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
- // THEN the plugin is the bubble clock face.
- ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
- verify(mMockListener1).onClockChanged(captor.capture());
- assertThat(captor.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- @Test
- public void onClockChanged_uniqueInstances() {
- // GIVEN that settings is set to the bubble clock face
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
- // WHEN settings change event is fired
- mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
- // THEN the listeners receive separate instances of the Bubble clock plugin.
- ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
- ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
- verify(mMockListener1).onClockChanged(captor1.capture());
- verify(mMockListener2).onClockChanged(captor2.capture());
- assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- assertThat(captor1.getValue()).isNotSameInstanceAs(captor2.getValue());
- }
-
- @Test
- public void getCurrentClock_badSettingsValue() {
- // GIVEN that settings contains a value that doesn't correspond to a
- // custom clock face.
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
- // WHEN settings change event is fired
- mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
- // THEN the result is null.
- assertThat(mClockManager.getCurrentClock()).isNull();
- }
-
- @Test
- public void getCurrentClock_dockedDefault() {
- // WHEN dock event is fired
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- // THEN the result is null, indicating the default clock face.
- assertThat(mClockManager.getCurrentClock()).isNull();
- }
-
- @Test
- public void getCurrentClock_dockedCustomClock() {
- // GIVEN settings is set to the bubble clock face
- when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
- // WHEN dock event fires
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- // THEN the plugin is the bubble clock face.
- assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- @Test
- public void getCurrentClock_badDockedSettingsValue() {
- // GIVEN settings contains a value that doesn't correspond to an available clock face.
- when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
- // WHEN dock event fires
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- // THEN the result is null.
- assertThat(mClockManager.getCurrentClock()).isNull();
- }
-
- @Test
- public void getCurrentClock_badDockedSettingsFallback() {
- // GIVEN settings contains a value that doesn't correspond to an available clock face, but
- // locked screen settings is set to bubble clock.
- when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn("bad value");
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
- // WHEN dock event is fired
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- // THEN the plugin is the bubble clock face.
- assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- @Test
- public void onUserChanged_defaultClock() {
- // WHEN the user changes
- switchUser(SECONDARY_USER_ID);
- // THEN the plugin is null for the default clock face
- assertThat(mClockManager.getCurrentClock()).isNull();
- }
-
- @Test
- public void onUserChanged_customClock() {
- // GIVEN that a second user has selected the bubble clock face
- when(mMockSettingsWrapper.getLockScreenCustomClockFace(SECONDARY_USER_ID)).thenReturn(
- BUBBLE_CLOCK);
- // WHEN the user changes
- switchUser(SECONDARY_USER_ID);
- // THEN the plugin is the bubble clock face.
- assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- @Test
- public void onUserChanged_docked() {
- // GIVEN device is docked
- mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
- // AND the second user as selected the bubble clock for the dock
- when(mMockSettingsWrapper.getDockedClockFace(SECONDARY_USER_ID)).thenReturn(BUBBLE_CLOCK);
- // WHEN the user changes
- switchUser(SECONDARY_USER_ID);
- // THEN the plugin is the bubble clock face.
- assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
- }
-
- private void switchUser(int newUser) {
- when(mUserTracker.getUserId()).thenReturn(newUser);
- mUserTrackerCallbackCaptor.getValue().onUserChanged(newUser, mContext);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
deleted file mode 100644
index d2832fb9..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
+++ /dev/null
@@ -1,189 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-
-import com.android.systemui.SysuiTestCase;
-
-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.List;
-import java.util.function.Supplier;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public final class ClockOptionsProviderTest extends SysuiTestCase {
-
- private static final String CONTENT_SCHEME = "content";
- private static final String AUTHORITY = "com.android.keyguard.clock";
- private static final String LIST_OPTIONS = "list_options";
- private static final String PREVIEW = "preview";
- private static final String THUMBNAIL = "thumbnail";
- private static final String MIME_TYPE_LIST_OPTIONS = "vnd.android.cursor.dir/clock_faces";
- private static final String MIME_TYPE_PNG = "image/png";
- private static final String NAME_COLUMN = "name";
- private static final String TITLE_COLUMN = "title";
- private static final String ID_COLUMN = "id";
- private static final String PREVIEW_COLUMN = "preview";
- private static final String THUMBNAIL_COLUMN = "thumbnail";
-
- private ClockOptionsProvider mProvider;
- private Supplier<List<ClockInfo>> mMockSupplier;
- private List<ClockInfo> mClocks;
- private Uri mListOptionsUri;
- @Mock
- private Supplier<Bitmap> mMockBitmapSupplier;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mClocks = new ArrayList<>();
- mProvider = new ClockOptionsProvider(() -> mClocks);
- mListOptionsUri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(LIST_OPTIONS)
- .build();
- }
-
- @Test
- public void testGetType_listOptions() {
- Uri uri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(LIST_OPTIONS)
- .build();
- assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_LIST_OPTIONS);
- }
-
- @Test
- public void testGetType_preview() {
- Uri uri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(PREVIEW)
- .appendPath("id")
- .build();
- assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_PNG);
- }
-
- @Test
- public void testGetType_thumbnail() {
- Uri uri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(THUMBNAIL)
- .appendPath("id")
- .build();
- assertThat(mProvider.getType(uri)).isEqualTo(MIME_TYPE_PNG);
- }
-
- @Test
- public void testQuery_noClocks() {
- Cursor cursor = mProvider.query(mListOptionsUri, null, null, null);
- assertThat(cursor.getCount()).isEqualTo(0);
- }
-
- @Test
- public void testQuery_listOptions() {
- mClocks.add(ClockInfo.builder()
- .setName("name_a")
- .setTitle(() -> "title_a")
- .setId("id_a")
- .build());
- mClocks.add(ClockInfo.builder()
- .setName("name_b")
- .setTitle(() -> "title_b")
- .setId("id_b")
- .build());
- Cursor cursor = mProvider.query(mListOptionsUri, null, null, null);
- assertThat(cursor.getCount()).isEqualTo(2);
- cursor.moveToFirst();
- assertThat(cursor.getString(
- cursor.getColumnIndex(NAME_COLUMN))).isEqualTo("name_a");
- assertThat(cursor.getString(
- cursor.getColumnIndex(TITLE_COLUMN))).isEqualTo("title_a");
- assertThat(cursor.getString(
- cursor.getColumnIndex(ID_COLUMN))).isEqualTo("id_a");
- assertThat(cursor.getString(
- cursor.getColumnIndex(PREVIEW_COLUMN)))
- .isEqualTo("content://com.android.keyguard.clock/preview/id_a");
- assertThat(cursor.getString(
- cursor.getColumnIndex(THUMBNAIL_COLUMN)))
- .isEqualTo("content://com.android.keyguard.clock/thumbnail/id_a");
- cursor.moveToNext();
- assertThat(cursor.getString(
- cursor.getColumnIndex(NAME_COLUMN))).isEqualTo("name_b");
- assertThat(cursor.getString(
- cursor.getColumnIndex(TITLE_COLUMN))).isEqualTo("title_b");
- assertThat(cursor.getString(
- cursor.getColumnIndex(ID_COLUMN))).isEqualTo("id_b");
- assertThat(cursor.getString(
- cursor.getColumnIndex(PREVIEW_COLUMN)))
- .isEqualTo("content://com.android.keyguard.clock/preview/id_b");
- assertThat(cursor.getString(
- cursor.getColumnIndex(THUMBNAIL_COLUMN)))
- .isEqualTo("content://com.android.keyguard.clock/thumbnail/id_b");
- }
-
- @Test
- public void testOpenFile_preview() throws Exception {
- mClocks.add(ClockInfo.builder()
- .setId("id")
- .setPreview(mMockBitmapSupplier)
- .build());
- Uri uri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(PREVIEW)
- .appendPath("id")
- .build();
- mProvider.openFile(uri, "r").close();
- verify(mMockBitmapSupplier).get();
- }
-
- @Test
- public void testOpenFile_thumbnail() throws Exception {
- mClocks.add(ClockInfo.builder()
- .setId("id")
- .setThumbnail(mMockBitmapSupplier)
- .build());
- Uri uri = new Uri.Builder()
- .scheme(CONTENT_SCHEME)
- .authority(AUTHORITY)
- .appendPath(THUMBNAIL)
- .appendPath("id")
- .build();
- mProvider.openFile(uri, "r").close();
- verify(mMockBitmapSupplier).get();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
deleted file mode 100644
index 347b26d..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
+++ /dev/null
@@ -1,97 +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.keyguard.clock
-
-import android.graphics.Color
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class ClockPaletteTest : SysuiTestCase() {
-
- private lateinit var clockPalette: ClockPalette
- private lateinit var colors: IntArray
-
- @Before
- fun setUp() {
- clockPalette = ClockPalette()
- // colors used are reds from light to dark.
- val hsv: FloatArray = FloatArray(3)
- Color.colorToHSV(Color.RED, hsv)
- colors = IntArray(10)
- val step: Float = (0f - hsv[2]) / colors.size
- for (i in 0 until colors.size) {
- hsv[2] += step
- colors[i] = Color.HSVToColor(hsv)
- }
- }
-
- @Test
- fun testDark() {
- // GIVEN on AOD
- clockPalette.setDarkAmount(1f)
- // AND GIVEN that wallpaper doesn't support dark text
- clockPalette.setColorPalette(false, colors)
- // THEN the secondary color should be lighter than the primary color
- assertThat(value(clockPalette.getPrimaryColor()))
- .isGreaterThan(value(clockPalette.getSecondaryColor()))
- }
-
- @Test
- fun testDarkText() {
- // GIVEN on lock screen
- clockPalette.setDarkAmount(0f)
- // AND GIVEN that wallpaper supports dark text
- clockPalette.setColorPalette(true, colors)
- // THEN the secondary color should be darker the primary color
- assertThat(value(clockPalette.getPrimaryColor()))
- .isLessThan(value(clockPalette.getSecondaryColor()))
- }
-
- @Test
- fun testLightText() {
- // GIVEN on lock screen
- clockPalette.setDarkAmount(0f)
- // AND GIVEN that wallpaper doesn't support dark text
- clockPalette.setColorPalette(false, colors)
- // THEN the secondary color should be darker than the primary color
- assertThat(value(clockPalette.getPrimaryColor()))
- .isGreaterThan(value(clockPalette.getSecondaryColor()))
- }
-
- @Test
- fun testNullColors() {
- // GIVEN on AOD
- clockPalette.setDarkAmount(1f)
- // AND GIVEN that wallpaper colors are null
- clockPalette.setColorPalette(false, null)
- // THEN the primary color should be whilte
- assertThat(clockPalette.getPrimaryColor()).isEqualTo(Color.WHITE)
- }
-
- private fun value(color: Int): Float {
- val hsv: FloatArray = FloatArray(3)
- Color.colorToHSV(color, hsv)
- return hsv[2]
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
deleted file mode 100644
index fd7657f..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
+++ /dev/null
@@ -1,94 +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.keyguard.clock;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public final class CrossFadeDarkControllerTest extends SysuiTestCase {
-
- private View mViewFadeIn;
- private View mViewFadeOut;
- private CrossFadeDarkController mDarkController;
-
- @Before
- public void setUp() {
- mViewFadeIn = new TextView(getContext());
- mViewFadeIn.setVisibility(View.VISIBLE);
- mViewFadeIn.setAlpha(1f);
- mViewFadeOut = new TextView(getContext());
- mViewFadeOut.setVisibility(View.VISIBLE);
- mViewFadeOut.setAlpha(1f);
-
- mDarkController = new CrossFadeDarkController(mViewFadeIn, mViewFadeOut);
- }
-
- @Test
- public void setDarkAmount_fadeIn() {
- // WHEN dark amount corresponds to AOD
- mDarkController.setDarkAmount(1f);
- // THEN fade in view should be faded in and fade out view faded out.
- assertThat(mViewFadeIn.getAlpha()).isEqualTo(1f);
- assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewFadeOut.getAlpha()).isEqualTo(0f);
- assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void setDarkAmount_fadeOut() {
- // WHEN dark amount corresponds to lock screen
- mDarkController.setDarkAmount(0f);
- // THEN fade out view should bed faded out and fade in view faded in.
- assertThat(mViewFadeIn.getAlpha()).isEqualTo(0f);
- assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewFadeOut.getAlpha()).isEqualTo(1f);
- assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void setDarkAmount_partialFadeIn() {
- // WHEN dark amount corresponds to a partial transition
- mDarkController.setDarkAmount(0.9f);
- // THEN views should have intermediate alpha value.
- assertThat(mViewFadeIn.getAlpha()).isGreaterThan(0f);
- assertThat(mViewFadeIn.getAlpha()).isLessThan(1f);
- assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void setDarkAmount_partialFadeOut() {
- // WHEN dark amount corresponds to a partial transition
- mDarkController.setDarkAmount(0.1f);
- // THEN views should have intermediate alpha value.
- assertThat(mViewFadeOut.getAlpha()).isGreaterThan(0f);
- assertThat(mViewFadeOut.getAlpha()).isLessThan(1f);
- assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt
deleted file mode 100644
index 573581d..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/SettingsWrapperTest.kt
+++ /dev/null
@@ -1,93 +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.keyguard.clock
-
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.json.JSONObject
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-
-private const val PACKAGE = "com.android.keyguard.clock.Clock"
-private const val CLOCK_FIELD = "clock"
-private const val TIMESTAMP_FIELD = "_applied_timestamp"
-private const val USER_ID = 0
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class SettingsWrapperTest : SysuiTestCase() {
-
- private lateinit var wrapper: SettingsWrapper
- private lateinit var migration: SettingsWrapper.Migration
-
- @Before
- fun setUp() {
- migration = mock(SettingsWrapper.Migration::class.java)
- wrapper = SettingsWrapper(getContext().contentResolver, migration)
- }
-
- @Test
- fun testDecodeUnnecessary() {
- // GIVEN a settings value that doesn't need to be decoded
- val value = PACKAGE
- // WHEN the value is decoded
- val decoded = wrapper.decode(value, USER_ID)
- // THEN the same value is returned, because decoding isn't necessary.
- // TODO(b/135674383): Null should be returned when the migration code in removed.
- assertThat(decoded).isEqualTo(value)
- // AND the value is migrated to JSON format
- verify(migration).migrate(value, USER_ID)
- }
-
- @Test
- fun testDecodeJSON() {
- // GIVEN a settings value that is encoded in JSON
- val json: JSONObject = JSONObject()
- json.put(CLOCK_FIELD, PACKAGE)
- json.put(TIMESTAMP_FIELD, System.currentTimeMillis())
- val value = json.toString()
- // WHEN the value is decoded
- val decoded = wrapper.decode(value, USER_ID)
- // THEN the clock field should have been extracted
- assertThat(decoded).isEqualTo(PACKAGE)
- }
-
- @Test
- fun testDecodeJSONWithoutClockField() {
- // GIVEN a settings value that doesn't contain the CLOCK_FIELD
- val json: JSONObject = JSONObject()
- json.put(TIMESTAMP_FIELD, System.currentTimeMillis())
- val value = json.toString()
- // WHEN the value is decoded
- val decoded = wrapper.decode(value, USER_ID)
- // THEN null is returned
- assertThat(decoded).isNull()
- // AND the value is not migrated to JSON format
- verify(migration, never()).migrate(value, USER_ID)
- }
-
- @Test
- fun testDecodeNullJSON() {
- assertThat(wrapper.decode(null, USER_ID)).isNull()
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt
deleted file mode 100644
index 3a27e35..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt
+++ /dev/null
@@ -1,67 +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.keyguard.clock
-
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class SmallClockPositionTest : SysuiTestCase() {
-
- private val statusBarHeight = 100
- private val lockPadding = 15
- private val lockHeight = 35
- private val burnInY = 20
-
- private lateinit var position: SmallClockPosition
-
- @Before
- fun setUp() {
- position = SmallClockPosition(statusBarHeight, lockPadding, lockHeight, burnInY)
- }
-
- @Test
- fun loadResources() {
- // Cover constructor taking Resources object.
- position = SmallClockPosition(context)
- position.setDarkAmount(1f)
- assertThat(position.preferredY).isGreaterThan(0)
- }
-
- @Test
- fun darkPosition() {
- // GIVEN on AOD
- position.setDarkAmount(1f)
- // THEN Y is sum of statusBarHeight, lockPadding, lockHeight, lockPadding, burnInY
- assertThat(position.preferredY).isEqualTo(185)
- }
-
- @Test
- fun lockPosition() {
- // GIVEN on lock screen
- position.setDarkAmount(0f)
- // THEN Y position is statusBarHeight + lockPadding + lockHeight + lockPadding
- // (100 + 15 + 35 + 15 = 165)
- assertThat(position.preferredY).isEqualTo(165)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
deleted file mode 100644
index 5ece6ef..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
+++ /dev/null
@@ -1,63 +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.keyguard.clock
-
-import android.content.Context
-import com.google.common.truth.Truth.assertThat
-
-import android.graphics.Canvas
-import android.graphics.Color
-import android.testing.AndroidTestingRunner
-import android.view.View
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class ViewPreviewerTest : SysuiTestCase() {
-
- private lateinit var previewer: ViewPreviewer
- private lateinit var view: View
-
- @Before
- fun setUp() {
- previewer = ViewPreviewer()
- view = TestView(context)
- }
-
- @Test
- fun testCreatePreview() {
- val width = 100
- val height = 100
- // WHEN a preview image is created
- val bitmap = previewer.createPreview(view, width, height)!!
- // THEN the bitmap has the expected width and height
- assertThat(bitmap.height).isEqualTo(height)
- assertThat(bitmap.width).isEqualTo(width)
- assertThat(bitmap.getPixel(0, 0)).isEqualTo(Color.RED)
- }
-
- class TestView(context: Context) : View(context) {
- override fun onDraw(canvas: Canvas?) {
- super.onDraw(canvas)
- canvas?.drawColor(Color.RED)
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
index 8207fa6..d500b5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
@@ -74,7 +74,8 @@
val decorationSupport = DisplayDecorationSupport()
decorationSupport.format = PixelFormat.R_8
- decorHwcLayer = Mockito.spy(ScreenDecorHwcLayer(mContext, decorationSupport))
+ decorHwcLayer =
+ Mockito.spy(ScreenDecorHwcLayer(mContext, decorationSupport, /* debug */ false))
whenever(decorHwcLayer.width).thenReturn(displayWidth)
whenever(decorHwcLayer.height).thenReturn(displayHeight)
whenever(decorHwcLayer.context).thenReturn(mockContext)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 4cf5a4b..79c87cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -43,7 +43,6 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -63,6 +62,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.PathParser;
import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout;
@@ -83,6 +83,7 @@
import com.android.systemui.decor.CornerDecorProvider;
import com.android.systemui.decor.CutoutDecorProviderFactory;
import com.android.systemui.decor.CutoutDecorProviderImpl;
+import com.android.systemui.decor.DebugRoundedCornerModel;
import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.FaceScanningOverlayProviderImpl;
@@ -96,7 +97,6 @@
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
-import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.FakeThreadFactory;
import com.android.systemui.util.settings.FakeSettings;
@@ -139,8 +139,6 @@
@Mock
private Display mDisplay;
@Mock
- private TunerService mTunerService;
- @Mock
private UserTracker mUserTracker;
@Mock
private PrivacyDotViewController mDotViewController;
@@ -234,7 +232,7 @@
new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer"))));
mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings,
- mTunerService, mUserTracker, mDisplayTracker, mDotViewController, mThreadFactory,
+ mUserTracker, mDisplayTracker, mDotViewController, mThreadFactory,
mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory,
new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")),
mAuthController) {
@@ -251,12 +249,6 @@
}
@Override
- public void onTuningChanged(String key, String newValue) {
- super.onTuningChanged(key, newValue);
- mExecutor.runAllReady();
- }
-
- @Override
protected void updateOverlayWindowVisibilityIfViewExists(@Nullable View view) {
super.updateOverlayWindowVisibilityIfViewExists(view);
mExecutor.runAllReady();
@@ -268,9 +260,10 @@
}
});
mScreenDecorations.mDisplayInfo = mDisplayInfo;
+ // Make sure tests are never run starting in debug mode
+ mScreenDecorations.setDebug(false);
doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
doNothing().when(mScreenDecorations).updateOverlayProviderViews(any());
- reset(mTunerService);
try {
mPrivacyDotShowingListener = mScreenDecorations.mPrivacyDotShowingListener.getClass()
@@ -464,8 +457,6 @@
mScreenDecorations.start();
// No views added.
verifyOverlaysExistAndAdded(false, false, false, false, null);
- // No Tuners tuned.
- verify(mTunerService, never()).addTunable(any(), any());
// No dot controller init
verify(mDotViewController, never()).initialize(any(), any(), any(), any());
}
@@ -497,8 +488,6 @@
// Face scanning doesn't exist
verifyFaceScanningViewExists(false);
- // One tunable.
- verify(mTunerService, times(1)).addTunable(any(), any());
// Dot controller init
verify(mDotViewController, times(1)).initialize(
isA(View.class), isA(View.class), isA(View.class), isA(View.class));
@@ -528,8 +517,6 @@
// Face scanning doesn't exist
verifyFaceScanningViewExists(false);
- // One tunable.
- verify(mTunerService, times(1)).addTunable(any(), any());
// No dot controller init
verify(mDotViewController, never()).initialize(any(), any(), any(), any());
}
@@ -560,8 +547,6 @@
// Face scanning doesn't exist
verifyFaceScanningViewExists(false);
- // One tunable.
- verify(mTunerService, times(1)).addTunable(any(), any());
// Dot controller init
verify(mDotViewController, times(1)).initialize(
isA(View.class), isA(View.class), isA(View.class), isA(View.class));
@@ -1073,18 +1058,89 @@
}
@Test
+ public void testDebugRoundedCorners_noDeviceCornersSet() {
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+ 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+
+ mScreenDecorations.start();
+ // No rounded corners exist at this point
+ verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
+
+ // Path from rounded.xml, scaled by 10x to produce 80x80 corners
+ Path debugPath = PathParser.createPathFromPathData("M8,0H0v8C0,3.6,3.6,0,8,0z");
+ // WHEN debug corners are added to the delegate
+ DebugRoundedCornerModel debugCorner = new DebugRoundedCornerModel(
+ debugPath,
+ 80,
+ 80,
+ 10f,
+ 10f
+ );
+ mScreenDecorations.mDebugRoundedCornerDelegate
+ .applyNewDebugCorners(debugCorner, debugCorner);
+
+ // AND debug mode is entered
+ mScreenDecorations.setDebug(true);
+ mExecutor.runAllReady();
+
+ // THEN the debug corners provide decor
+ List<DecorProvider> providers = mScreenDecorations.getProviders(false);
+ assertEquals(4, providers.size());
+
+ // Top and bottom overlays contain the debug rounded corners
+ verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
+ }
+
+ @Test
+ public void testDebugRoundedCornersRemoved_noDeviceCornersSet() {
+ // GIVEN a device with no rounded corners defined
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+ 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+
+ mScreenDecorations.start();
+ // No rounded corners exist at this point
+ verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
+
+ // Path from rounded.xml, scaled by 10x to produce 80x80 corners
+ Path debugPath = PathParser.createPathFromPathData("M8,0H0v8C0,3.6,3.6,0,8,0z");
+ // WHEN debug corners are added to the delegate
+ DebugRoundedCornerModel debugCorner = new DebugRoundedCornerModel(
+ debugPath,
+ 80,
+ 80,
+ 10f,
+ 10f
+ );
+ mScreenDecorations.mDebugRoundedCornerDelegate
+ .applyNewDebugCorners(debugCorner, debugCorner);
+
+ // AND debug mode is entered
+ mScreenDecorations.setDebug(true);
+ mExecutor.runAllReady();
+
+ // Top and bottom overlays contain the debug rounded corners
+ verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
+
+ // WHEN debug is exited
+ mScreenDecorations.setDebug(false);
+ mExecutor.runAllReady();
+
+ // THEN the decor is removed
+ verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
+ assertThat(mScreenDecorations.mDebugRoundedCornerDelegate.getHasBottom()).isFalse();
+ assertThat(mScreenDecorations.mDebugRoundedCornerDelegate.getHasTop()).isFalse();
+ }
+
+ @Test
public void testRegistration_From_NoOverlay_To_HasOverlays() {
doReturn(false).when(mScreenDecorations).hasOverlays();
mScreenDecorations.start();
- verify(mTunerService, times(0)).addTunable(any(), any());
- verify(mTunerService, times(1)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(false));
- reset(mTunerService);
doReturn(true).when(mScreenDecorations).hasOverlays();
mScreenDecorations.onConfigurationChanged(new Configuration());
- verify(mTunerService, times(1)).addTunable(any(), any());
- verify(mTunerService, times(0)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(true));
}
@@ -1093,14 +1149,9 @@
doReturn(true).when(mScreenDecorations).hasOverlays();
mScreenDecorations.start();
- verify(mTunerService, times(1)).addTunable(any(), any());
- verify(mTunerService, times(0)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(true));
- reset(mTunerService);
mScreenDecorations.onConfigurationChanged(new Configuration());
- verify(mTunerService, times(0)).addTunable(any(), any());
- verify(mTunerService, times(0)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(true));
}
@@ -1109,15 +1160,10 @@
doReturn(true).when(mScreenDecorations).hasOverlays();
mScreenDecorations.start();
- verify(mTunerService, times(1)).addTunable(any(), any());
- verify(mTunerService, times(0)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(true));
- reset(mTunerService);
doReturn(false).when(mScreenDecorations).hasOverlays();
mScreenDecorations.onConfigurationChanged(new Configuration());
- verify(mTunerService, times(0)).addTunable(any(), any());
- verify(mTunerService, times(1)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(false));
}
@@ -1181,7 +1227,7 @@
when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(true);
ScreenDecorations screenDecorations = new ScreenDecorations(mContext, mExecutor,
- mSecureSettings, mTunerService, mUserTracker, mDisplayTracker, mDotViewController,
+ mSecureSettings, mUserTracker, mDisplayTracker, mDotViewController,
mThreadFactory, mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory,
new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")), mAuthController);
screenDecorations.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt
new file mode 100644
index 0000000..deacac3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.AccessibilityLogger.MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_CLOSED
+import com.android.systemui.accessibility.AccessibilityLogger.MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AccessibilityLoggerTest : SysuiTestCase() {
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
+ private val fakeClock = FakeSystemClock()
+ @Mock private lateinit var fakeLogger: UiEventLogger
+
+ private lateinit var a11yLogger: AccessibilityLogger
+
+ @Before
+ fun setup() {
+ a11yLogger = AccessibilityLogger(fakeLogger, fakeClock)
+ }
+
+ @Test
+ fun logThrottled_onceWithinWindow() {
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ fakeClock.advanceTime(100L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ fakeClock.advanceTime(900L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ fakeClock.advanceTime(1100L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+
+ verify(fakeLogger, times(2)).log(eq(MAGNIFICATION_SETTINGS_PANEL_OPENED))
+ }
+
+ @Test
+ fun logThrottled_interlacedLogsAllWithinWindow() {
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_CLOSED, 1000)
+ fakeClock.advanceTime(100L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_CLOSED, 1000)
+ fakeClock.advanceTime(200L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+ fakeClock.advanceTime(1100L)
+ a11yLogger.logThrottled(MAGNIFICATION_SETTINGS_PANEL_OPENED, 1000)
+
+ verify(fakeLogger, times(3)).log(eq(MAGNIFICATION_SETTINGS_PANEL_OPENED))
+ verify(fakeLogger).log(eq(MAGNIFICATION_SETTINGS_PANEL_CLOSED))
+ }
+}
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 db58074..104ca69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -117,6 +117,8 @@
return null;
}).when(mMagnificationSettingsController).closeMagnificationSettings();
+ when(mWindowMagnificationController.isActivated()).thenReturn(true);
+
mCommandQueue = new CommandQueue(getContext(), mDisplayTracker);
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
@@ -199,8 +201,10 @@
waitForIdleSync();
verify(mMagnificationSettingsController).toggleSettingsPanelVisibility();
- verify(mA11yLogger).log(
- eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED));
+ verify(mA11yLogger).logWithPosition(
+ eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_PANEL_OPENED),
+ eq(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)
+ );
}
@Test
@@ -211,8 +215,10 @@
waitForIdleSync();
verify(mWindowMagnificationController).changeMagnificationSize(eq(index));
- verify(mA11yLogger).log(
- eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED));
+ verify(mA11yLogger).logWithPosition(
+ eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_WINDOW_SIZE_SELECTED),
+ eq(index)
+ );
}
@Test
@@ -253,6 +259,8 @@
TEST_DISPLAY, scale);
verify(mConnectionCallback).onPerformScaleAction(eq(TEST_DISPLAY), eq(scale));
+ verify(mA11yLogger).logThrottled(
+ eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
index f6ca938..fd258e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
@@ -29,7 +29,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.bubbles.DismissView;
+import com.android.wm.shell.bubbles.DismissViewUtils;
+import com.android.wm.shell.common.bubbles.DismissView;
import org.junit.Before;
import org.junit.Rule;
@@ -63,6 +64,7 @@
final MenuView stubMenuView = new MenuView(mContext, stubMenuViewModel,
stubMenuViewAppearance);
mDismissView = spy(new DismissView(mContext));
+ DismissViewUtils.setup(mDismissView);
mDismissAnimationController = new DismissAnimationController(mDismissView, stubMenuView);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index d4efbe4..98be49f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -40,7 +40,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.MotionEventHelper;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.wm.shell.bubbles.DismissView;
+import com.android.wm.shell.bubbles.DismissViewUtils;
+import com.android.wm.shell.common.bubbles.DismissView;
import org.junit.After;
import org.junit.Before;
@@ -88,6 +89,7 @@
mStubMenuView.setTranslationY(0);
mMenuAnimationController = spy(new MenuAnimationController(mStubMenuView));
mDismissView = spy(new DismissView(mContext));
+ DismissViewUtils.setup(mDismissView);
mDismissAnimationController =
spy(new DismissAnimationController(mDismissView, mStubMenuView));
mTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
index f10c21b..a10f5dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.whenever
@@ -38,6 +39,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
+import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -63,6 +65,7 @@
.getResources()
.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+ @Mock private lateinit var userTracker: UserTracker
@Captor
private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener>
@@ -72,7 +75,7 @@
val mainHandler = Handler(TestableLooper.get(this).getLooper())
systemSettings = FakeSettings()
// Guarantee that the systemSettings always starts with the default font scale.
- systemSettings.putFloat(Settings.System.FONT_SCALE, 1.0f)
+ systemSettings.putFloatForUser(Settings.System.FONT_SCALE, 1.0f, userTracker.userId)
secureSettings = FakeSettings()
systemClock = FakeSystemClock()
backgroundDelayableExecutor = FakeExecutor(systemClock)
@@ -82,6 +85,7 @@
systemSettings,
secureSettings,
systemClock,
+ userTracker,
mainHandler,
backgroundDelayableExecutor
)
@@ -93,7 +97,12 @@
val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!!
val progress: Int = seekBar.getProgress()
- val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
+ val currentScale =
+ systemSettings.getFloatForUser(
+ Settings.System.FONT_SCALE,
+ /* def= */ 1.0f,
+ userTracker.userId
+ )
assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat())
@@ -119,7 +128,12 @@
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
- val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
+ val currentScale =
+ systemSettings.getFloatForUser(
+ Settings.System.FONT_SCALE,
+ /* def= */ 1.0f,
+ userTracker.userId
+ )
assertThat(seekBar.getProgress()).isEqualTo(1)
assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat())
@@ -145,7 +159,12 @@
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
- val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
+ val currentScale =
+ systemSettings.getFloatForUser(
+ Settings.System.FONT_SCALE,
+ /* def= */ 1.0f,
+ userTracker.userId
+ )
assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
assertThat(currentScale)
.isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat())
@@ -159,16 +178,21 @@
val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
- secureSettings.putInt(Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, OFF)
+ secureSettings.putIntForUser(
+ Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+ OFF,
+ userTracker.userId
+ )
// Default seekbar progress for font size is 1, set it to another progress 0
seekBarWithIconButtonsView.setProgress(0)
backgroundDelayableExecutor.runAllReady()
val currentSettings =
- secureSettings.getInt(
+ secureSettings.getIntForUser(
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
- /* def = */ OFF
+ /* def = */ OFF,
+ userTracker.userId
)
assertThat(currentSettings).isEqualTo(ON)
@@ -199,7 +223,12 @@
backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size remains the default value 1.0f.
- var systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
+ var systemScale =
+ systemSettings.getFloatForUser(
+ Settings.System.FONT_SCALE,
+ /* def= */ 1.0f,
+ userTracker.userId
+ )
assertThat(systemScale).isEqualTo(1.0f)
// Simulate releasing the finger from the seekbar.
@@ -209,7 +238,12 @@
backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size has been updated.
- systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
+ systemScale =
+ systemSettings.getFloatForUser(
+ Settings.System.FONT_SCALE,
+ /* def= */ 1.0f,
+ userTracker.userId
+ )
assertThat(systemScale).isEqualTo(fontSizeValueArray[0].toFloat())
fontScalingDialog.dismiss()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 3a93e77..ac2d492 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -337,6 +337,110 @@
}
@Test
+ fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNullAndHasNoEffect() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(), tryAutoConfirm = true)).isNull()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(0)
+ }
+
+ @Test
+ fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(1, 2, 3), tryAutoConfirm = true)).isNull()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(0)
+ }
+
+ @Test
+ fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(1)
+ }
+
+ @Test
+ fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4, 5), tryAutoConfirm = true))
+ .isFalse()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(1)
+ }
+
+ @Test
+ fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(1)
+ }
+
+ @Test
+ fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = false)
+ )
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(0)
+ }
+
+ @Test
+ fun tryAutoConfirm_withoutCorrectPassword_returnsNullAndHasNoEffects() =
+ testScope.runTest {
+ val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ assertThat(isUnlocked).isFalse()
+
+ assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
+ assertThat(isUnlocked).isFalse()
+ assertThat(failedAttemptCount).isEqualTo(0)
+ }
+
+ @Test
fun unlocksDevice_whenAuthMethodBecomesNone() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
new file mode 100644
index 0000000..88c710a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.back.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.QuickSettingsController
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BackActionInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var shadeController: ShadeController
+ @Mock private lateinit var qsController: QuickSettingsController
+ @Mock private lateinit var shadeViewController: ShadeViewController
+
+ private lateinit var backActionInteractor: BackActionInteractor
+
+ @Before
+ fun setup() {
+ backActionInteractor =
+ BackActionInteractor(
+ statusBarStateController,
+ statusBarKeyguardViewManager,
+ shadeController,
+ )
+ backActionInteractor.setup(qsController, shadeViewController)
+ }
+
+ @Test
+ fun testOnBackRequested_keyguardCanHandleBackPressed() {
+ whenever(statusBarKeyguardViewManager.canHandleBackPressed()).thenReturn(true)
+
+ val result = backActionInteractor.onBackRequested()
+
+ assertTrue(result)
+ verify(statusBarKeyguardViewManager, atLeastOnce()).onBackPressed()
+ }
+
+ @Test
+ fun testOnBackRequested_quickSettingsIsCustomizing() {
+ whenever(qsController.isCustomizing).thenReturn(true)
+
+ val result = backActionInteractor.onBackRequested()
+
+ assertTrue(result)
+ verify(qsController, atLeastOnce()).closeQsCustomizer()
+ verify(statusBarKeyguardViewManager, never()).onBackPressed()
+ }
+
+ @Test
+ fun testOnBackRequested_quickSettingsExpanded() {
+ whenever(qsController.expanded).thenReturn(true)
+
+ val result = backActionInteractor.onBackRequested()
+
+ assertTrue(result)
+ verify(shadeViewController, atLeastOnce()).animateCollapseQs(anyBoolean())
+ verify(statusBarKeyguardViewManager, never()).onBackPressed()
+ }
+
+ @Test
+ fun testOnBackRequested_closeUserSwitcherIfOpen() {
+ whenever(shadeViewController.closeUserSwitcherIfOpen()).thenReturn(true)
+
+ val result = backActionInteractor.onBackRequested()
+
+ assertTrue(result)
+ verify(statusBarKeyguardViewManager, never()).onBackPressed()
+ verify(shadeViewController, never()).animateCollapseQs(anyBoolean())
+ }
+
+ @Test
+ fun testOnBackRequested_returnsFalse() {
+ // make shouldBackBeHandled return false
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+ val result = backActionInteractor.onBackRequested()
+
+ assertFalse(result)
+ verify(statusBarKeyguardViewManager, never()).onBackPressed()
+ verify(shadeViewController, never()).animateCollapseQs(anyBoolean())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index b4a4a11..5cae23c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -492,6 +492,50 @@
}
@Test
+ public void testOnAuthenticationFailedInvoked_whenFaceAuthRejected() throws RemoteException {
+ final int modality = BiometricAuthenticator.TYPE_FACE;
+ final int userId = 0;
+
+ enrollFingerprintAndFace(userId);
+
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+
+ mAuthController.onBiometricError(modality,
+ BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
+ 0 /* vendorCode */);
+
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+
+ assertEquals(modalityCaptor.getValue().intValue(), modality);
+ assertEquals(messageCaptor.getValue(),
+ mContext.getString(R.string.biometric_face_not_recognized));
+ }
+
+ @Test
+ public void testOnAuthenticationFailedInvoked_whenFingerprintAuthRejected() {
+ final int modality = BiometricAuthenticator.TYPE_FINGERPRINT;
+ final int userId = 0;
+
+ enrollFingerprintAndFace(userId);
+
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+
+ mAuthController.onBiometricError(modality,
+ BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
+ 0 /* vendorCode */);
+
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+
+ assertEquals(modalityCaptor.getValue().intValue(), modality);
+ assertEquals(messageCaptor.getValue(),
+ mContext.getString(R.string.fingerprint_error_not_match));
+ }
+
+ @Test
public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_FACE;
@@ -1017,6 +1061,31 @@
return HAT;
}
+ private void enrollFingerprintAndFace(final int userId) {
+
+ // Enroll fingerprint
+ verify(mFingerprintManager).registerBiometricStateListener(
+ mBiometricStateCaptor.capture());
+ assertFalse(mAuthController.isFingerprintEnrolled(userId));
+
+ mBiometricStateCaptor.getValue().onEnrollmentsChanged(userId,
+ 1 /* sensorId */, true /* hasEnrollments */);
+ waitForIdleSync();
+
+ assertTrue(mAuthController.isFingerprintEnrolled(userId));
+
+ // Enroll face
+ verify(mFaceManager).registerBiometricStateListener(
+ mBiometricStateCaptor.capture());
+ assertFalse(mAuthController.isFaceAuthEnrolled(userId));
+
+ mBiometricStateCaptor.getValue().onEnrollmentsChanged(userId,
+ 2 /* sensorId */, true /* hasEnrollments */);
+ waitForIdleSync();
+
+ assertTrue(mAuthController.isFaceAuthEnrolled(userId));
+ }
+
private final class TestableAuthController extends AuthController {
private int mBuildCount = 0;
private PromptInfo mLastBiometricPromptInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index ef750be..9cabd35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -20,12 +20,12 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shade.ShadeExpansionStateManager
+import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.junit.MockitoJUnit
@@ -63,10 +63,10 @@
}
@Test
- fun testEnableDetector_expandOnly_shouldPostRunnable() {
+ fun testEnableDetector_expandOnly_shouldNotPostRunnable() {
detector.enable(action)
shadeExpansionStateManager.onPanelExpansionChanged(1.0f, true, false, 0f)
- verify(action).run()
+ verifyZeroInteractions(action)
}
@Test
@@ -84,4 +84,14 @@
shadeExpansionStateManager.onPanelExpansionChanged(1.0f, true, true, 0f)
verifyZeroInteractions(action)
}
+
+ @Test
+ fun testFromOpenState_becomeStateClose_enableDetector_shouldNotPostRunnable() {
+ // STATE_OPEN is 2
+ shadeExpansionStateManager.updateState(2)
+ detector.enable(action)
+ shadeExpansionStateManager.onPanelExpansionChanged(0.5f, false, false, 0f)
+ verifyZeroInteractions(action)
+ Assert.assertEquals(true, shadeExpansionStateManager.isClosed())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 72cd822..821c2cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -443,6 +443,16 @@
}
@Test
+ public void showUdfpsOverlay_callsListener() throws RemoteException {
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
+ TEST_REQUEST_ID, mOpticalProps.sensorId);
+ }
+
+ @Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
@@ -762,17 +772,20 @@
inOrder.verify(mAlternateTouchProvider).onUiReady();
inOrder.verify(mLatencyTracker).onActionEnd(
eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
- verify(mFingerprintManager, never()).onUiReady(anyLong(), anyInt());
+ verify(mFingerprintManager, never()).onUdfpsUiEvent(
+ eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
} else {
InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
- inOrder.verify(mFingerprintManager).onUiReady(eq(TEST_REQUEST_ID),
+ inOrder.verify(mFingerprintManager).onUdfpsUiEvent(
+ eq(FingerprintManager.UDFPS_UI_READY), eq(TEST_REQUEST_ID),
eq(testParams.sensorProps.sensorId));
inOrder.verify(mLatencyTracker).onActionEnd(
eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
verify(mAlternateTouchProvider, never()).onUiReady();
}
} else {
- verify(mFingerprintManager, never()).onUiReady(anyLong(), anyInt());
+ verify(mFingerprintManager, never()).onUdfpsUiEvent(
+ eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
verify(mAlternateTouchProvider, never()).onUiReady();
verify(mLatencyTracker, never()).onActionEnd(
eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
new file mode 100644
index 0000000..0df4fbf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
+
+import android.database.ContentObserver
+import android.os.Handler
+import android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.captureMany
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.SecureSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+private const val USER_ID = 8
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class FaceSettingsRepositoryImplTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+ private val testScope = TestScope()
+
+ @Mock private lateinit var mainHandler: Handler
+ @Mock private lateinit var secureSettings: SecureSettings
+
+ private lateinit var repository: FaceSettingsRepositoryImpl
+
+ @Before
+ fun setup() {
+ repository = FaceSettingsRepositoryImpl(mainHandler, secureSettings)
+ }
+
+ @Test
+ fun createsOneRepositoryPerUser() =
+ testScope.runTest {
+ val userRepo = repository.forUser(USER_ID)
+
+ assertThat(userRepo.userId).isEqualTo(USER_ID)
+
+ assertThat(repository.forUser(USER_ID)).isSameInstanceAs(userRepo)
+ assertThat(repository.forUser(USER_ID + 1)).isNotSameInstanceAs(userRepo)
+ }
+
+ @Test
+ fun startsRepoImmediatelyWithAllSettingKeys() =
+ testScope.runTest {
+ val userRepo = repository.forUser(USER_ID)
+
+ val keys =
+ captureMany<String> {
+ verify(secureSettings)
+ .registerContentObserverForUser(capture(), anyBoolean(), any(), eq(USER_ID))
+ }
+
+ assertThat(keys).containsExactly(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION)
+ }
+
+ @Test
+ fun forwardsSettingsValues() = runTest {
+ val userRepo = repository.forUser(USER_ID)
+
+ val intAsBooleanSettings =
+ listOf(
+ FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION to
+ collectLastValue(userRepo.alwaysRequireConfirmationInApps)
+ )
+
+ for ((setting, accessor) in intAsBooleanSettings) {
+ val observer =
+ withArgCaptor<ContentObserver> {
+ verify(secureSettings)
+ .registerContentObserverForUser(
+ eq(setting),
+ anyBoolean(),
+ capture(),
+ eq(USER_ID)
+ )
+ }
+
+ for (value in listOf(true, false)) {
+ secureSettings.mockIntSetting(setting, if (value) 1 else 0)
+ observer.onChange(false)
+ assertThat(accessor()).isEqualTo(value)
+ }
+ }
+ }
+
+ private fun SecureSettings.mockIntSetting(key: String, value: Int) {
+ whenever(getIntForUser(eq(key), anyInt(), eq(USER_ID))).thenReturn(value)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
index 4836af6..ec7ce63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
import android.hardware.biometrics.PromptInfo
@@ -5,12 +21,16 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.shared.model.PromptKind
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -21,61 +41,109 @@
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+private const val USER_ID = 9
+private const val CHALLENGE = 90L
+
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class PromptRepositoryImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+ private val testScope = TestScope()
+ private val faceSettings = FakeFaceSettingsRepository()
+
@Mock private lateinit var authController: AuthController
private lateinit var repository: PromptRepositoryImpl
@Before
fun setup() {
- repository = PromptRepositoryImpl(authController)
+ repository = PromptRepositoryImpl(faceSettings, authController)
}
@Test
- fun isShowing() = runBlockingTest {
- whenever(authController.isShowing).thenReturn(true)
+ fun isShowing() =
+ testScope.runTest {
+ whenever(authController.isShowing).thenReturn(true)
- val values = mutableListOf<Boolean>()
- val job = launch { repository.isShowing.toList(values) }
- assertThat(values).containsExactly(true)
+ val values = mutableListOf<Boolean>()
+ val job = launch { repository.isShowing.toList(values) }
+ runCurrent()
- withArgCaptor<AuthController.Callback> {
- verify(authController).addCallback(capture())
+ assertThat(values).containsExactly(true)
- value.onBiometricPromptShown()
- assertThat(values).containsExactly(true, true)
+ withArgCaptor<AuthController.Callback> {
+ verify(authController).addCallback(capture())
- value.onBiometricPromptDismissed()
- assertThat(values).containsExactly(true, true, false).inOrder()
+ value.onBiometricPromptShown()
+ runCurrent()
+ assertThat(values).containsExactly(true, true)
- job.cancel()
- verify(authController).removeCallback(eq(value))
+ value.onBiometricPromptDismissed()
+ runCurrent()
+ assertThat(values).containsExactly(true, true, false).inOrder()
+
+ job.cancel()
+ runCurrent()
+ verify(authController).removeCallback(eq(value))
+ }
}
- }
@Test
- fun setsAndUnsetsPrompt() = runBlockingTest {
- val kind = PromptKind.Pin
- val uid = 8
- val challenge = 90L
- val promptInfo = PromptInfo()
+ fun isConfirmationRequired_whenNotForced() =
+ testScope.runTest {
+ faceSettings.setUserSettings(USER_ID, alwaysRequireConfirmationInApps = false)
+ val isConfirmationRequired by collectLastValue(repository.isConfirmationRequired)
- repository.setPrompt(promptInfo, uid, challenge, kind)
+ for (case in listOf(true, false)) {
+ repository.setPrompt(
+ PromptInfo().apply { isConfirmationRequested = case },
+ USER_ID,
+ CHALLENGE,
+ PromptKind.Biometric()
+ )
- assertThat(repository.kind.value).isEqualTo(kind)
- assertThat(repository.userId.value).isEqualTo(uid)
- assertThat(repository.challenge.value).isEqualTo(challenge)
- assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
+ assertThat(isConfirmationRequired).isEqualTo(case)
+ }
+ }
- repository.unsetPrompt()
+ @Test
+ fun isConfirmationRequired_whenForced() =
+ testScope.runTest {
+ faceSettings.setUserSettings(USER_ID, alwaysRequireConfirmationInApps = true)
+ val isConfirmationRequired by collectLastValue(repository.isConfirmationRequired)
- assertThat(repository.promptInfo.value).isNull()
- assertThat(repository.userId.value).isNull()
- assertThat(repository.challenge.value).isNull()
- }
+ for (case in listOf(true, false)) {
+ repository.setPrompt(
+ PromptInfo().apply { isConfirmationRequested = case },
+ USER_ID,
+ CHALLENGE,
+ PromptKind.Biometric()
+ )
+
+ assertThat(isConfirmationRequired).isTrue()
+ }
+ }
+
+ @Test
+ fun setsAndUnsetsPrompt() =
+ testScope.runTest {
+ val kind = PromptKind.Pin
+ val promptInfo = PromptInfo()
+
+ repository.setPrompt(promptInfo, USER_ID, CHALLENGE, kind)
+
+ assertThat(repository.kind.value).isEqualTo(kind)
+ assertThat(repository.userId.value).isEqualTo(USER_ID)
+ assertThat(repository.challenge.value).isEqualTo(CHALLENGE)
+ assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
+
+ repository.unsetPrompt()
+
+ assertThat(repository.promptInfo.value).isNull()
+ assertThat(repository.userId.value).isNull()
+ assertThat(repository.challenge.value).isNull()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index a62ea3b..81cbaea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -106,17 +106,11 @@
val currentPrompt by collectLastValue(interactor.prompt)
val credentialKind by collectLastValue(interactor.credentialKind)
val isCredentialAllowed by collectLastValue(interactor.isCredentialAllowed)
- val isExplicitConfirmationRequired by collectLastValue(interactor.isConfirmationRequested)
+ val isExplicitConfirmationRequired by collectLastValue(interactor.isConfirmationRequired)
assertThat(currentPrompt).isNull()
- interactor.useBiometricsForAuthentication(
- info,
- confirmationRequired,
- USER_ID,
- CHALLENGE,
- modalities
- )
+ interactor.useBiometricsForAuthentication(info, USER_ID, CHALLENGE, modalities)
assertThat(currentPrompt).isNotNull()
assertThat(currentPrompt?.title).isEqualTo(TITLE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 3ba6004..5b3edab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -631,7 +631,6 @@
}
useBiometricsForAuthentication(
info,
- requireConfirmation,
USER_ID,
CHALLENGE,
BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 6a63c32..9483667 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -95,6 +95,61 @@
}
@Test
+ fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val message by collectLastValue(underTest.message)
+
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ authenticationInteractor.lockDevice()
+ underTest.showOrUnlockDevice("container1")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
+ underTest.clearMessage()
+
+ // Incomplete input.
+ assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true)).isNull()
+ assertThat(message).isEmpty()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ // Wrong 4-digit pin
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 5), tryAutoConfirm = true)).isFalse()
+ assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ // Correct input.
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isTrue()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
+ }
+
+ @Test
+ fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val message by collectLastValue(underTest.message)
+
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = false)
+ )
+ authenticationInteractor.lockDevice()
+ underTest.showOrUnlockDevice("container1")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.clearMessage()
+
+ // Incomplete input.
+ assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true)).isNull()
+ assertThat(message).isEmpty()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ // Correct input.
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
+ assertThat(message).isEmpty()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ }
+
+ @Test
fun passwordAuthMethod() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 7b6bb37..7e358d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -286,15 +285,160 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
+ @Test
+ fun onAutoConfirm_whenCorrect() =
+ testScope.runTest {
+ val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
+ val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ authenticationInteractor.lockDevice()
+ sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+ underTest.onPinButtonClicked(1)
+ underTest.onPinButtonClicked(2)
+ underTest.onPinButtonClicked(3)
+ underTest.onPinButtonClicked(4)
+
+ assertThat(isUnlocked).isTrue()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
+ }
+
+ @Test
+ fun onAutoConfirm_whenWrong() =
+ testScope.runTest {
+ val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
+ val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val message by collectLastValue(bouncerViewModel.message)
+ val entries by collectLastValue(underTest.pinEntries)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+ authenticationInteractor.lockDevice()
+ sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+ underTest.onPinButtonClicked(1)
+ underTest.onPinButtonClicked(2)
+ underTest.onPinButtonClicked(3)
+ underTest.onPinButtonClicked(5) // PIN is now wrong!
+
+ assertThat(entries).hasSize(0)
+ assertThat(message?.text).isEqualTo(WRONG_PIN)
+ assertThat(isUnlocked).isFalse()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ }
+
+ @Test
+ fun backspaceButtonAppearance_withoutAutoConfirm_alwaysShown() =
+ testScope.runTest {
+ val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
+
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = false)
+ )
+
+ assertThat(backspaceButtonAppearance).isEqualTo(ActionButtonAppearance.Shown)
+ }
+
+ @Test
+ fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
+ testScope.runTest {
+ val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+
+ assertThat(backspaceButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
+ }
+
+ @Test
+ fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
+ testScope.runTest {
+ val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+
+ underTest.onPinButtonClicked(1)
+
+ assertThat(backspaceButtonAppearance).isEqualTo(ActionButtonAppearance.Subtle)
+ }
+
+ @Test
+ fun confirmButtonAppearance_withoutAutoConfirm_alwaysShown() =
+ testScope.runTest {
+ val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
+
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = false)
+ )
+
+ assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Shown)
+ }
+
+ @Test
+ fun confirmButtonAppearance_withAutoConfirm_isHidden() =
+ testScope.runTest {
+ val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = true)
+ )
+
+ assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
+ }
+
+ @Test
+ fun hintedPinLength_withoutAutoConfirm_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234, autoConfirm = false)
+ )
+
+ assertThat(hintedPinLength).isNull()
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(12345, autoConfirm = true)
+ )
+
+ assertThat(hintedPinLength).isNull()
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(123456, autoConfirm = true)
+ )
+
+ assertThat(hintedPinLength).isEqualTo(6)
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ authenticationInteractor.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
+ )
+
+ assertThat(hintedPinLength).isNull()
+ }
+
companion object {
private const val CONTAINER_NAME = "container1"
private const val ENTER_YOUR_PIN = "Enter your pin"
private const val WRONG_PIN = "Wrong pin"
-
- val KEY_CODE =
- Correspondence.transforming<EnteredKey, Int>(
- { it?.input },
- "has a eventId of",
- )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 292fdff..f770a38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -187,4 +187,11 @@
when(mFalsingDataProvider.isUnfolded()).thenReturn(true);
assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
}
+
+ @Test
+ public void testTrackpadGesture() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ when(mFalsingDataProvider.isFromTrackpad()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 9254617..4da151c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -18,8 +18,11 @@
import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.util.DisplayMetrics;
+import android.view.InputDevice;
import android.view.MotionEvent;
+import androidx.test.uiautomator.Configurator;
+
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -80,6 +83,10 @@
mDataProvider.onSessionEnd();
}
+ protected static int getPointerAction(int actionType, int index) {
+ return actionType + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ }
+
protected MotionEvent appendDownEvent(float x, float y) {
return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y);
}
@@ -124,4 +131,55 @@
return motionEvent;
}
+
+ protected MotionEvent appendTrackpadDownEvent(float x, float y) {
+ return appendTrackpadMotionEvent(MotionEvent.ACTION_DOWN, x, y, 1);
+ }
+
+ protected MotionEvent appendTrackpadMoveEvent(float x, float y, int pointerCount) {
+ return appendTrackpadMotionEvent(MotionEvent.ACTION_MOVE, x, y, pointerCount);
+ }
+
+ protected MotionEvent appendTrackpadPointerDownEvent(int actionType, float x, float y,
+ int pointerCount) {
+ return appendTrackpadMotionEvent(actionType, x, y, pointerCount);
+ }
+
+ private MotionEvent appendTrackpadMotionEvent(int actionType, float x, float y,
+ int pointerCount) {
+ long eventTime = mMotionEvents.isEmpty() ? 1 : mMotionEvents.get(
+ mMotionEvents.size() - 1).getEventTime() + 1;
+ return appendTrackpadMotionEvent(actionType, x, y, pointerCount, eventTime);
+ }
+
+ private MotionEvent appendTrackpadMotionEvent(int actionType, float x, float y,
+ int pointerCount, long eventTime) {
+ MotionEvent.PointerProperties[] pointerProperties =
+ new MotionEvent.PointerProperties[pointerCount];
+ MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
+ for (int i = 0; i < pointerCount; i++) {
+ pointerProperties[i] = getPointerProperties(i);
+ pointerCoords[i] = getPointerCoords(x, y);
+ }
+ return MotionEvent.obtain(1, eventTime, actionType, pointerCount, pointerProperties,
+ pointerCoords, 0, 0, 1.0f, 1.0f, 0, 0,
+ InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE, 0, 0,
+ MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE);
+ }
+
+ private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
+ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = pointerId;
+ properties.toolType = Configurator.getInstance().getToolType();
+ return properties;
+ }
+
+ private static MotionEvent.PointerCoords getPointerCoords(float x, float y) {
+ MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+ coords.pressure = 1;
+ coords.size = 1;
+ coords.x = x;
+ coords.y = y;
+ return coords;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 7e06680..0353f87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -282,6 +282,22 @@
}
@Test
+ public void test_IsFromTrackpad() {
+ MotionEvent motionEventOrigin = appendTrackpadDownEvent(0, 0);
+
+ mDataProvider.onMotionEvent(motionEventOrigin);
+ mDataProvider.onMotionEvent(
+ appendTrackpadPointerDownEvent(getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
+ 0, 0, 2));
+ mDataProvider.onMotionEvent(
+ appendTrackpadPointerDownEvent(getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+ 0, 0, 3));
+ mDataProvider.onMotionEvent(appendTrackpadMoveEvent(1, -1, 3));
+ assertThat(mDataProvider.isFromTrackpad()).isTrue();
+ mDataProvider.onSessionEnd();
+ }
+
+ @Test
public void test_isWirelessCharging() {
assertThat(mDataProvider.isDocked()).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 39fb7b4..9671966 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -26,6 +26,7 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
+import static com.android.systemui.flags.Flags.CLIPBOARD_SHARED_TRANSITIONS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -93,12 +94,16 @@
@Mock
private ClipboardImageLoader mClipboardImageLoader;
@Mock
+ private ClipboardTransitionExecutor mClipboardTransitionExecutor;
+ @Mock
private UiEventLogger mUiEventLogger;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock
private Animator mAnimator;
+ private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor =
+ ArgumentCaptor.forClass(Animator.AnimatorListener.class);
private ClipData mSampleClipData;
@@ -117,6 +122,7 @@
when(mClipboardOverlayView.getEnterAnimation()).thenReturn(mAnimator);
when(mClipboardOverlayView.getExitAnimation()).thenReturn(mAnimator);
+ when(mClipboardOverlayView.getFadeOutAnimation()).thenReturn(mAnimator);
when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
getImeInsets(new Rect(0, 0, 0, 0)));
@@ -124,7 +130,16 @@
new ClipData.Item("Test Item"));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
+ mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, true); // turned off for old tests
+ }
+ /**
+ * Needs to be done after setting flags for legacy tests, since the value of
+ * CLIPBOARD_SHARED_TRANSITIONS is checked during construction. This can be moved back into
+ * the setup method once CLIPBOARD_SHARED_TRANSITIONS is fully released and the tests where it
+ * is false are removed.[
+ */
+ private void initController() {
mOverlayController = new ClipboardOverlayController(
mContext,
mClipboardOverlayView,
@@ -136,6 +151,7 @@
mClipboardUtils,
mExecutor,
mClipboardImageLoader,
+ mClipboardTransitionExecutor,
mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -148,6 +164,8 @@
@Test
public void test_setClipData_invalidImageData_legacy() {
+ initController();
+
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
@@ -161,6 +179,8 @@
@Test
public void test_setClipData_nonImageUri_legacy() {
+ initController();
+
ClipData clipData = new ClipData("", new String[]{"resource/png"},
new ClipData.Item(Uri.parse("")));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
@@ -175,6 +195,8 @@
@Test
public void test_setClipData_textData_legacy() {
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ initController();
+
mOverlayController.setClipData(mSampleClipData, "abc");
verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
@@ -186,6 +208,8 @@
@Test
public void test_setClipData_sensitiveTextData_legacy() {
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ initController();
+
ClipDescription description = mSampleClipData.getDescription();
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
@@ -202,6 +226,7 @@
public void test_setClipData_repeatedCalls_legacy() {
when(mAnimator.isRunning()).thenReturn(true);
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
+ initController();
mOverlayController.setClipData(mSampleClipData, "");
mOverlayController.setClipData(mSampleClipData, "");
@@ -211,6 +236,8 @@
@Test
public void test_setClipData_invalidImageData() {
+ initController();
+
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
@@ -223,6 +250,7 @@
@Test
public void test_setClipData_nonImageUri() {
+ initController();
ClipData clipData = new ClipData("", new String[]{"resource/png"},
new ClipData.Item(Uri.parse("")));
@@ -235,6 +263,7 @@
@Test
public void test_setClipData_textData() {
+ initController();
mOverlayController.setClipData(mSampleClipData, "abc");
verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
@@ -245,6 +274,7 @@
@Test
public void test_setClipData_sensitiveTextData() {
+ initController();
ClipDescription description = mSampleClipData.getDescription();
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
@@ -259,6 +289,7 @@
@Test
public void test_setClipData_repeatedCalls() {
+ initController();
when(mAnimator.isRunning()).thenReturn(true);
mOverlayController.setClipData(mSampleClipData, "");
@@ -268,7 +299,9 @@
}
@Test
- public void test_viewCallbacks_onShareTapped() {
+ public void test_viewCallbacks_onShareTapped_sharedTransitionsOff() {
+ mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
+ initController();
mOverlayController.setClipData(mSampleClipData, "");
mCallbacks.onShareButtonTapped();
@@ -278,7 +311,22 @@
}
@Test
- public void test_viewCallbacks_onDismissTapped() {
+ public void test_viewCallbacks_onShareTapped() {
+ initController();
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ mCallbacks.onShareButtonTapped();
+ verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
+ mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator);
+
+ verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "");
+ verify(mClipboardOverlayView, times(1)).getFadeOutAnimation();
+ }
+
+ @Test
+ public void test_viewCallbacks_onDismissTapped_sharedTransitionsOff() {
+ mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
+ initController();
mOverlayController.setClipData(mSampleClipData, "");
mCallbacks.onDismissButtonTapped();
@@ -288,7 +336,35 @@
}
@Test
+ public void test_viewCallbacks_onDismissTapped() {
+ initController();
+
+ mCallbacks.onDismissButtonTapped();
+ verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
+ mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator);
+
+ // package name is null since we haven't actually set a source for this test
+ verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, null);
+ verify(mClipboardOverlayView, times(1)).getExitAnimation();
+ }
+
+ @Test
+ public void test_multipleDismissals_dismissesOnce_sharedTransitionsOff() {
+ mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
+ initController();
+ mCallbacks.onSwipeDismissInitiated(mAnimator);
+ mCallbacks.onDismissButtonTapped();
+ mCallbacks.onSwipeDismissInitiated(mAnimator);
+ mCallbacks.onDismissButtonTapped();
+
+ verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED, 0, null);
+ verify(mUiEventLogger, never()).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
+ }
+
+ @Test
public void test_multipleDismissals_dismissesOnce() {
+ initController();
+
mCallbacks.onSwipeDismissInitiated(mAnimator);
mCallbacks.onDismissButtonTapped();
mCallbacks.onSwipeDismissInitiated(mAnimator);
@@ -300,6 +376,7 @@
@Test
public void test_remoteCopy_withFlagOn() {
+ initController();
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
mOverlayController.setClipData(mSampleClipData, "");
@@ -309,6 +386,7 @@
@Test
public void test_nonRemoteCopy() {
+ initController();
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false);
mOverlayController.setClipData(mSampleClipData, "");
@@ -318,13 +396,16 @@
@Test
public void test_logsUseLastClipSource() {
- mOverlayController.setClipData(mSampleClipData, "first.package");
- mCallbacks.onDismissButtonTapped();
- mOverlayController.setClipData(mSampleClipData, "second.package");
- mCallbacks.onDismissButtonTapped();
+ initController();
- verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "first.package");
- verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "second.package");
+ mOverlayController.setClipData(mSampleClipData, "first.package");
+ mCallbacks.onShareButtonTapped();
+
+ mOverlayController.setClipData(mSampleClipData, "second.package");
+ mCallbacks.onShareButtonTapped();
+
+ verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "first.package");
+ verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "second.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "first.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "second.package");
verifyNoMoreInteractions(mUiEventLogger);
@@ -332,6 +413,7 @@
@Test
public void test_logOnClipboardActionsShown() {
+ initController();
ClipData.Item item = mSampleClipData.getItemAt(0);
item.setTextLinks(Mockito.mock(TextLinks.class));
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
@@ -357,6 +439,7 @@
@Test
public void test_noInsets_showsExpanded() {
+ initController();
mOverlayController.setClipData(mSampleClipData, "");
verify(mClipboardOverlayView, never()).setMinimized(true);
@@ -366,6 +449,7 @@
@Test
public void test_insets_showsMinimized() {
+ initController();
when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
getImeInsets(new Rect(0, 0, 0, 1)));
mOverlayController.setClipData(mSampleClipData, "abc");
@@ -389,6 +473,7 @@
@Test
public void test_insetsChanged_minimizes() {
+ initController();
mOverlayController.setClipData(mSampleClipData, "");
verify(mClipboardOverlayView, never()).setMinimized(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
index fcc3589..8f0b193 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
@@ -39,7 +39,7 @@
@Before
fun setUp() {
- roundedCornerResDelegate = spy(RoundedCornerResDelegate(mContext.resources, null))
+ roundedCornerResDelegate = spy(RoundedCornerResDelegateImpl(mContext.resources, null))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index 93a1868..4feba7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -48,7 +48,7 @@
@Test
fun testTopAndBottomRoundedCornerExist() {
setupResources(radius = 5)
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(true, roundedCornerResDelegate.hasTop)
assertEquals(true, roundedCornerResDelegate.hasBottom)
}
@@ -56,7 +56,7 @@
@Test
fun testTopRoundedCornerExist() {
setupResources(radiusTop = 10)
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(true, roundedCornerResDelegate.hasTop)
assertEquals(false, roundedCornerResDelegate.hasBottom)
}
@@ -64,7 +64,7 @@
@Test
fun testBottomRoundedCornerExist() {
setupResources(radiusBottom = 15)
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(false, roundedCornerResDelegate.hasTop)
assertEquals(true, roundedCornerResDelegate.hasBottom)
}
@@ -75,7 +75,7 @@
roundedTopDrawable = getTestsDrawable(R.drawable.rounded3px),
roundedBottomDrawable = getTestsDrawable(R.drawable.rounded4px))
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
@@ -96,7 +96,7 @@
roundedTopDrawable = getTestsDrawable(R.drawable.rounded3px),
roundedBottomDrawable = getTestsDrawable(R.drawable.rounded4px))
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
@@ -109,33 +109,12 @@
}
@Test
- fun testUpdateTuningSizeFactor() {
- setupResources(radius = 100,
- roundedTopDrawable = getTestsDrawable(R.drawable.rounded3px),
- roundedBottomDrawable = getTestsDrawable(R.drawable.rounded4px))
-
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
-
- val factor = 5
- roundedCornerResDelegate.tuningSizeFactor = factor
- val length = (factor * mContext.resources.displayMetrics.density).toInt()
-
- assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
- assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize)
-
- roundedCornerResDelegate.tuningSizeFactor = null
-
- assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
- assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
- }
-
- @Test
fun testPhysicalPixelDisplaySizeChanged() {
setupResources(
roundedTopDrawable = getTestsDrawable(R.drawable.rounded4px),
roundedBottomDrawable = getTestsDrawable(R.drawable.rounded4px))
- roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ roundedCornerResDelegate = RoundedCornerResDelegateImpl(mContext.resources, null)
assertEquals(Size(4, 4), roundedCornerResDelegate.topRoundedSize)
assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
index d934f76..39fcd41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard;
+import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
@@ -42,6 +43,7 @@
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -81,8 +83,10 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mView.getTextColors()).thenReturn(ColorStateList.valueOf(Color.WHITE));
+ FakeFeatureFlags flags = new FakeFeatureFlags();
+ flags.set(KEYGUARD_TALKBACK_FIX, true);
mController = new KeyguardIndicationRotateTextViewController(mView, mExecutor,
- mStatusBarStateController, mLogger);
+ mStatusBarStateController, mLogger, flags);
mController.onViewAttached();
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index b0c1a34..b324b4713 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -24,8 +24,11 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
+import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
+import static com.android.systemui.keyguard.KeyguardViewMediator.SYS_BOOT_REASON_PROP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -86,6 +89,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -172,6 +176,8 @@
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Captor ArgumentCaptor<KeyguardUpdateMonitorCallback>
mKeyguardUpdateMonitorCallbackCaptor;
+ private @Captor ArgumentCaptor<KeyguardStateController.Callback>
+ mKeyguardStateControllerCallback;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -190,6 +196,7 @@
private @Mock CoroutineDispatcher mDispatcher;
private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
+ private @Mock SystemPropertiesHelper mSystemPropertiesHelper;
private FakeFeatureFlags mFeatureFlags;
private int mInitialUserId;
@@ -421,6 +428,59 @@
}
@Test
+ public void testBouncerPrompt_deviceRestartedDueToMainlineUpdate() {
+ // GIVEN biometrics enrolled
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
+
+ // WHEN reboot caused by ota update
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(false);
+ when(mSystemPropertiesHelper.get(SYS_BOOT_REASON_PROP)).thenReturn(REBOOT_MAINLINE_UPDATE);
+
+ // THEN the bouncer prompt reason should return PROMPT_REASON_RESTART_FOR_OTA
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
+ public void testBouncerPrompt_afterUserLockDown() {
+ // GIVEN biometrics enrolled
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
+
+ // WHEN user has locked down the device
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+ .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ // THEN the bouncer prompt reason should return PROMPT_REASON_USER_REQUEST
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_USER_REQUEST,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
+ public void testBouncerPrompt_afterUserLockDown_noBiometricsEnrolled() {
+ // GIVEN biometrics not enrolled
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+ // WHEN user has locked down the device
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+ .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ // THEN the bouncer prompt reason should return the default prompt
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_NONE,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
public void testBouncerPrompt_nonStrongIdleTimeout() {
// GIVEN trust agents enabled and biometrics are enrolled
when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(true);
@@ -782,6 +842,33 @@
);
}
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void pendingPinLockOnKeyguardGoingAway_doKeyguardLockedOnKeyguardVisibilityChanged() {
+ // GIVEN SIM_STATE_PIN_REQUIRED
+ mViewMediator.onSystemReady();
+ final KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback =
+ mViewMediator.mUpdateCallback;
+ keyguardUpdateMonitorCallback.onSimStateChanged(0, 0,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ TestableLooper.get(this).processAllMessages();
+
+ // ...and then the primary bouncer shows while the keyguard is going away
+ captureKeyguardStateControllerCallback();
+ when(mKeyguardStateController.isPrimaryBouncerShowing()).thenReturn(true);
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
+ mKeyguardStateControllerCallback.getValue().onPrimaryBouncerShowingChanged();
+ TestableLooper.get(this).processAllMessages();
+
+ // WHEN keyguard visibility becomes FALSE
+ mViewMediator.setShowingLocked(false);
+ keyguardUpdateMonitorCallback.onKeyguardVisibilityChanged(false);
+ TestableLooper.get(this).processAllMessages();
+
+ // THEN keyguard shows due to the pending SIM PIN lock
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
+ }
+
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
@@ -822,7 +909,8 @@
mSystemSettings,
mSystemClock,
mDispatcher,
- () -> mDreamingToLockscreenTransitionViewModel);
+ () -> mDreamingToLockscreenTransitionViewModel,
+ mSystemPropertiesHelper);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
@@ -831,4 +919,8 @@
private void captureKeyguardUpdateMonitorCallback() {
verify(mUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallbackCaptor.capture());
}
+
+ private void captureKeyguardStateControllerCallback() {
+ verify(mKeyguardStateController).addCallback(mKeyguardStateControllerCallback.capture());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 92ec9a1..5922cbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -507,6 +507,18 @@
}
@Test
+ fun authenticateDoesNotRunIfKeyguardIsNotShowing() =
+ testScope.runTest {
+ testGatingCheckForFaceAuth { keyguardRepository.setKeyguardShowing(false) }
+ }
+
+ @Test
+ fun detectDoesNotRunIfKeyguardIsNotShowing() =
+ testScope.runTest {
+ testGatingCheckForDetect { keyguardRepository.setKeyguardShowing(false) }
+ }
+
+ @Test
fun authenticateDoesNotRunWhenFpIsLockedOut() =
testScope.runTest {
testGatingCheckForFaceAuth { deviceEntryFingerprintAuthRepository.setLockedOut(true) }
@@ -565,6 +577,8 @@
testScope.runTest {
testGatingCheckForFaceAuth {
bouncerRepository.setAlternateVisible(false)
+ // Keyguard is occluded when secure camera is active.
+ keyguardRepository.setKeyguardOccluded(true)
fakeCommandQueue.doForEachCallback {
it.onCameraLaunchGestureDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
}
@@ -774,6 +788,8 @@
testScope.runTest {
testGatingCheckForDetect {
bouncerRepository.setAlternateVisible(false)
+ // Keyguard is occluded when secure camera is active.
+ keyguardRepository.setKeyguardOccluded(true)
fakeCommandQueue.doForEachCallback {
it.onCameraLaunchGestureDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
}
@@ -1011,6 +1027,7 @@
fakeUserRepository.setSelectedUserInfo(primaryUser)
biometricSettingsRepository.setIsFaceAuthSupportedInCurrentPosture(true)
bouncerRepository.setAlternateVisible(true)
+ keyguardRepository.setKeyguardShowing(true)
runCurrent()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 2aff90c..5b8272b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -19,7 +19,9 @@
import android.app.PendingIntent
import android.content.res.ColorStateList
import android.content.res.Configuration
+import android.database.ContentObserver
import android.os.LocaleList
+import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.util.MathUtils.abs
@@ -56,6 +58,7 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.FakeSystemClock
import java.util.Locale
import javax.inject.Provider
@@ -113,6 +116,7 @@
@Mock lateinit var mediaFlags: MediaFlags
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock lateinit var globalSettings: GlobalSettings
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor
@@ -120,6 +124,7 @@
@Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
@Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@Captor lateinit var hostStateCallback: ArgumentCaptor<MediaHostStatesManager.Callback>
+ @Captor lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -148,6 +153,7 @@
mediaFlags,
keyguardUpdateMonitor,
KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
+ globalSettings
)
verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener))
@@ -160,6 +166,11 @@
whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
MediaPlayerData.clear()
+ verify(globalSettings)
+ .registerContentObserver(
+ eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
+ settingsObserverCaptor.capture()
+ )
}
@Test
@@ -873,6 +884,15 @@
assertTrue(stateUpdated)
}
+ @Test
+ fun testAnimationScaleChanged_mediaControlPanelsNotified() {
+ MediaPlayerData.addMediaPlayer("key", DATA, panel, clock, isSsReactivated = false)
+
+ globalSettings.putFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 0f)
+ settingsObserverCaptor.value!!.onChange(false)
+ verify(panel).updateAnimatorDurationScale()
+ }
+
/**
* Helper method when a configuration change occurs.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index f6075ad..f902be3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -25,7 +25,6 @@
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
-import android.database.ContentObserver
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
@@ -113,7 +112,6 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
-import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
@@ -239,7 +237,6 @@
this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false)
}
@Mock private lateinit var globalSettings: GlobalSettings
- @Captor private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -281,7 +278,7 @@
lockscreenUserManager,
broadcastDialogController,
fakeFeatureFlag,
- globalSettings,
+ globalSettings
) {
override fun loadAnimator(
animId: Int,
@@ -292,12 +289,6 @@
}
}
- verify(globalSettings)
- .registerContentObserver(
- eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
- settingsObserverCaptor.capture()
- )
-
initGutsViewHolderMocks()
initMediaViewHolderMocks()
@@ -986,7 +977,7 @@
// When the setting changes,
globalSettings.putFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 0f)
- settingsObserverCaptor.value!!.onChange(false)
+ player.updateAnimatorDurationScale()
// Then the seekbar is set to not animate
assertThat(seekBarObserver.animationEnabled).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index f3aee48..a14ff2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -356,6 +356,7 @@
});
verify(mockMediaOutputController).releaseSession();
+ verify(mDialogLaunchAnimator).disableAllCurrentDialogsExitAnimations();
}
@Test
@@ -371,7 +372,7 @@
@NonNull
private MediaOutputDialog makeTestDialog(MediaOutputController controller) {
return new MediaOutputDialog(mContext, false, mBroadcastSender,
- controller, mUiEventLogger);
+ controller, mDialogLaunchAnimator, mUiEventLogger);
}
private void withTestDialog(MediaOutputController controller, Consumer<MediaOutputDialog> c) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 25d494c..697d1a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -20,7 +20,6 @@
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
-import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
@@ -364,7 +363,7 @@
externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE,
BACK_DISPOSITION_DEFAULT, true);
defaultNavBar.setImeWindowStatus(
- DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false);
+ DEFAULT_DISPLAY, null, 0 /* vis */, BACK_DISPOSITION_DEFAULT, false);
// Verify IME window state will be updated in external NavBar & default NavBar state reset.
assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN
| NAVIGATION_HINT_IME_SWITCHER_SHOWN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
index aacc695..93f316e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -49,7 +49,7 @@
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString()
val expectedLogString = disableFlagsLogger.getDisableFlagsString(
- old = null, new = state, newAfterLocalModification = state
+ new = state, newAfterLocalModification = state
)
assertThat(actualString).contains(expectedLogString)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
index f55d262..180fed9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -155,6 +155,28 @@
inOrder.verify(d).stop();
}
+ @Test
+ public void testAnimatorCallbackRemovedOnOldDrawable() {
+ ImageView iv = new ImageView(mContext);
+ AnimatedVectorDrawable d1 = mock(AnimatedVectorDrawable.class);
+ when(d1.getConstantState()).thenReturn(fakeConstantState(d1));
+ AnimatedVectorDrawable d2 = mock(AnimatedVectorDrawable.class);
+ when(d2.getConstantState()).thenReturn(fakeConstantState(d2));
+ State s = new State();
+ s.isTransient = true;
+
+ // When set Animatable2 d1
+ s.icon = new QSTileImpl.DrawableIcon(d1);
+ mIconView.updateIcon(iv, s, true);
+
+ // And then set Animatable2 d2
+ s.icon = new QSTileImpl.DrawableIcon(d2);
+ mIconView.updateIcon(iv, s, true);
+
+ // Then d1 has its callback cleared
+ verify(d1).clearAnimationCallbacks();
+ }
+
private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) {
return new Drawable.ConstantState() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index ddbfca5..cbc3553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -33,6 +33,8 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -44,8 +46,11 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -61,6 +66,8 @@
@Mock private lateinit var qsLogger: QSLogger
@Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
@Mock private lateinit var uiEventLogger: QsEventLogger
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
private lateinit var testableLooper: TestableLooper
private lateinit var systemClock: FakeSystemClock
@@ -69,6 +76,8 @@
val featureFlags = FakeFeatureFlags()
+ @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -88,11 +97,13 @@
statusBarStateController,
activityStarter,
qsLogger,
+ keyguardStateController,
dialogLaunchAnimator,
FakeSettings(),
FakeSettings(),
FakeSystemClock(),
featureFlags,
+ userTracker,
backgroundDelayableExecutor,
)
fontScalingTile.initialize()
@@ -124,15 +135,45 @@
}
@Test
- fun clickTile_showDialog() {
+ fun clickTile_screenUnlocked_showDialogAnimationFromView() {
+ `when`(keyguardStateController.isShowing).thenReturn(false)
val view = View(context)
fontScalingTile.click(view)
testableLooper.processAllMessages()
+ verify(activityStarter)
+ .executeRunnableDismissingKeyguard(
+ argumentCaptor.capture(),
+ eq(null),
+ eq(true),
+ eq(true),
+ eq(false)
+ )
+ argumentCaptor.value.run()
verify(dialogLaunchAnimator).showFromView(any(), eq(view), nullable(), anyBoolean())
}
@Test
+ fun clickTile_onLockScreen_neverShowDialogAnimationFromView() {
+ `when`(keyguardStateController.isShowing).thenReturn(true)
+ val view = View(context)
+ fontScalingTile.click(view)
+ testableLooper.processAllMessages()
+
+ verify(activityStarter)
+ .executeRunnableDismissingKeyguard(
+ argumentCaptor.capture(),
+ eq(null),
+ eq(true),
+ eq(true),
+ eq(false)
+ )
+ argumentCaptor.value.run()
+ verify(dialogLaunchAnimator, never())
+ .showFromView(any(), eq(view), nullable(), anyBoolean())
+ }
+
+ @Test
fun getLongClickIntent_getExpectedIntent() {
val intent: Intent? = fontScalingTile.getLongClickIntent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 6614392..5b30687 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -968,6 +968,7 @@
assertThat(mInternetDialogController.mSubIdTelephonyManagerMap.get(SUB_ID)).isEqualTo(
mTelephonyManager);
assertThat(mInternetDialogController.mSubIdTelephonyCallbackMap.get(SUB_ID)).isNotNull();
+ assertThat(mInternetDialogController.mCallback).isNotNull();
mInternetDialogController.onStop();
@@ -980,6 +981,7 @@
verify(mAccessPointController).removeAccessPointCallback(mInternetDialogController);
verify(mConnectivityManager).unregisterNetworkCallback(
any(ConnectivityManager.NetworkCallback.class));
+ assertThat(mInternetDialogController.mCallback).isNull();
}
private String getResourcesString(String name) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
index ab321f1..ba3d392 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
@@ -26,7 +26,7 @@
import android.os.RemoteException;
import android.view.Display;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
-import android.window.ScreenCapture.ScreenshotSync;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import androidx.test.runner.AndroidJUnit4;
@@ -58,7 +58,7 @@
@Mock private Optional<Bubbles> mBubblesOptional;
@Mock private Bubbles mBubbles;
@Mock private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
- @Mock private ScreenshotSync mScreenshotSync;
+ @Mock private SynchronousScreenCaptureListener mScreenshotSync;
private AppClipsScreenshotHelperService mAppClipsScreenshotHelperService;
@@ -80,7 +80,7 @@
when(mBubblesOptional.isEmpty()).thenReturn(false);
when(mBubblesOptional.get()).thenReturn(mBubbles);
when(mBubbles.getScreenshotExcludingBubble(DEFAULT_DISPLAY)).thenReturn(mScreenshotSync);
- when(mScreenshotSync.get()).thenReturn(null);
+ when(mScreenshotSync.getBuffer()).thenReturn(null);
assertThat(getInterface().takeScreenshot(DEFAULT_DISPLAY)).isNull();
}
@@ -90,7 +90,7 @@
when(mBubblesOptional.isEmpty()).thenReturn(false);
when(mBubblesOptional.get()).thenReturn(mBubbles);
when(mBubbles.getScreenshotExcludingBubble(DEFAULT_DISPLAY)).thenReturn(mScreenshotSync);
- when(mScreenshotSync.get()).thenReturn(mScreenshotHardwareBuffer);
+ when(mScreenshotSync.getBuffer()).thenReturn(mScreenshotHardwareBuffer);
when(mScreenshotHardwareBuffer.getHardwareBuffer()).thenReturn(FAKE_HARDWARE_BUFFER);
when(mScreenshotHardwareBuffer.getColorSpace()).thenReturn(FAKE_COLOR_SPACE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
index 3706859..0a1eca6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
@@ -62,9 +62,9 @@
assertThat(getConstraint(R.id.clock).layout.startToStart).isEqualTo(R.id.begin_guide)
assertThat(getConstraint(R.id.clock).layout.horizontalBias).isEqualTo(0f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).layout.endToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.endToEnd)
.isEqualTo(R.id.end_guide)
- assertThat(getConstraint(R.id.batteryRemainingIcon).layout.horizontalBias)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.horizontalBias)
.isEqualTo(1f)
assertThat(getConstraint(R.id.privacy_container).layout.endToEnd)
@@ -95,9 +95,9 @@
assertThat(getConstraint(R.id.date).layout.startToStart).isEqualTo(PARENT_ID)
assertThat(getConstraint(R.id.date).layout.horizontalBias).isEqualTo(0.5f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).layout.endToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.endToEnd)
.isEqualTo(PARENT_ID)
- assertThat(getConstraint(R.id.batteryRemainingIcon).layout.horizontalBias)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.horizontalBias)
.isEqualTo(0.5f)
assertThat(getConstraint(R.id.privacy_container).layout.endToEnd)
@@ -133,18 +133,15 @@
changes()
with(qqsConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(1f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(1f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(1f)
}
with(qsConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(1f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(1f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(1f)
}
with(largeScreenConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(1f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(1f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(1f)
}
}
@@ -155,18 +152,15 @@
changes()
with(qqsConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(0f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(0f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(0f)
}
with(qsConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(1f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(1f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(1f)
}
with(largeScreenConstraint) {
- assertThat(getConstraint(R.id.statusIcons).propertySet.alpha).isEqualTo(1f)
- assertThat(getConstraint(R.id.batteryRemainingIcon).propertySet.alpha).isEqualTo(1f)
+ assertThat(systemIconsAlphaConstraint).isEqualTo(1f)
}
}
@@ -181,12 +175,13 @@
with(qqsConstraint) {
// In this case, the date is constrained on the end by a Barrier determined by either
- // privacy or statusIcons
+ // privacy or clickableIcons
assertThat(getConstraint(R.id.date).layout.endToStart).isEqualTo(R.id.barrier)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd).isEqualTo(R.id.date)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
+ .isEqualTo(R.id.date)
assertThat(getConstraint(R.id.privacy_container).layout.startToEnd).isEqualTo(R.id.date)
assertThat(getConstraint(R.id.barrier).layout.mReferenceIds).asList().containsExactly(
- R.id.statusIcons,
+ R.id.shade_header_system_icons,
R.id.privacy_container
)
assertThat(getConstraint(R.id.barrier).layout.mBarrierDirection).isEqualTo(START)
@@ -272,7 +267,7 @@
assertThat(getConstraint(R.id.center_left).layout.guideBegin).isEqualTo(offsetFromEdge)
assertThat(getConstraint(R.id.center_right).layout.guideEnd).isEqualTo(offsetFromEdge)
assertThat(getConstraint(R.id.date).layout.endToStart).isEqualTo(R.id.center_left)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isEqualTo(R.id.center_right)
assertThat(getConstraint(R.id.privacy_container).layout.startToEnd)
.isEqualTo(R.id.center_right)
@@ -285,9 +280,9 @@
assertThat(getConstraint(R.id.date).layout.endToStart).isNotEqualTo(R.id.center_left)
assertThat(getConstraint(R.id.date).layout.endToStart).isNotEqualTo(R.id.center_right)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isNotEqualTo(R.id.center_left)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isNotEqualTo(R.id.center_right)
assertThat(getConstraint(R.id.privacy_container).layout.startToEnd)
@@ -311,7 +306,7 @@
assertThat(getConstraint(R.id.center_left).layout.guideEnd).isEqualTo(offsetFromEdge)
assertThat(getConstraint(R.id.center_right).layout.guideBegin).isEqualTo(offsetFromEdge)
assertThat(getConstraint(R.id.date).layout.endToStart).isEqualTo(R.id.center_right)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isEqualTo(R.id.center_left)
assertThat(getConstraint(R.id.privacy_container).layout.startToEnd)
.isEqualTo(R.id.center_left)
@@ -324,9 +319,9 @@
assertThat(getConstraint(R.id.date).layout.endToStart).isNotEqualTo(R.id.center_left)
assertThat(getConstraint(R.id.date).layout.endToStart).isNotEqualTo(R.id.center_right)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isNotEqualTo(R.id.center_left)
- assertThat(getConstraint(R.id.statusIcons).layout.startToEnd)
+ assertThat(getConstraint(R.id.shade_header_system_icons).layout.startToEnd)
.isNotEqualTo(R.id.center_right)
assertThat(getConstraint(R.id.privacy_container).layout.startToEnd)
@@ -382,7 +377,8 @@
CombinedShadeHeadersConstraintManagerImpl.emptyCutoutConstraints()()
assertThat(qqsConstraint.getConstraint(R.id.date).layout.constrainedWidth).isTrue()
- assertThat(qqsConstraint.getConstraint(R.id.statusIcons).layout.constrainedWidth).isTrue()
+ val shadeHeaderConstraint = qqsConstraint.getConstraint(R.id.shade_header_system_icons)
+ assertThat(shadeHeaderConstraint.layout.constrainedWidth).isTrue()
}
@Test
@@ -390,9 +386,13 @@
CombinedShadeHeadersConstraintManagerImpl.centerCutoutConstraints(false, 10)()
assertThat(qqsConstraint.getConstraint(R.id.date).layout.constrainedWidth).isTrue()
- assertThat(qqsConstraint.getConstraint(R.id.statusIcons).layout.constrainedWidth).isTrue()
+ val shadeHeaderConstraint = qqsConstraint.getConstraint(R.id.shade_header_system_icons)
+ assertThat(shadeHeaderConstraint.layout.constrainedWidth).isTrue()
}
+ private val ConstraintSet.systemIconsAlphaConstraint
+ get() = getConstraint(R.id.shade_header_system_icons).propertySet.alpha
+
private operator fun ConstraintsChanges.invoke() {
qqsConstraintsChanges?.invoke(qqsConstraint)
qsConstraintsChanges?.invoke(qsConstraint)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 46ced82..20804b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -117,6 +117,7 @@
import com.android.systemui.qs.QSFragment;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.data.repository.ShadeRepository;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -168,6 +169,7 @@
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -311,6 +313,8 @@
@Mock protected ActivityStarter mActivityStarter;
@Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
@Mock protected ShadeRepository mShadeRepository;
+ @Mock private ShadeInteractor mShadeInteractor;
+ @Mock private JavaAdapter mJavaAdapter;
@Mock private CastController mCastController;
protected final int mMaxUdfpsBurnInOffsetY = 5;
@@ -688,6 +692,8 @@
mDumpManager,
mKeyguardFaceAuthInteractor,
mShadeRepository,
+ mShadeInteractor,
+ mJavaAdapter,
mCastController
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 470c824..5802eb3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@@ -733,6 +734,47 @@
}
@Test
+ public void onQsSetExpansionHeightCalled_qsFullyExpandedOnKeyguard_showNSSL() {
+ // GIVEN
+ mStatusBarStateController.setState(KEYGUARD);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false);
+ when(mQsController.getFullyExpanded()).thenReturn(true);
+ when(mQsController.getExpanded()).thenReturn(true);
+
+ // WHEN
+ int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
+ mNotificationPanelViewController.setExpandedHeight(transitionDistance);
+
+ // THEN
+ // We are interested in the last value of the stack alpha.
+ ArgumentCaptor<Float> alphaCaptor = ArgumentCaptor.forClass(Float.class);
+ verify(mNotificationStackScrollLayoutController, atLeastOnce())
+ .setAlpha(alphaCaptor.capture());
+ assertThat(alphaCaptor.getValue()).isEqualTo(1.0f);
+ }
+
+ @Test
+ public void onQsSetExpansionHeightCalled_qsFullyExpandedOnKeyguard_hideNSSL() {
+ // GIVEN
+ mStatusBarStateController.setState(KEYGUARD);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false);
+ when(mQsController.getFullyExpanded()).thenReturn(false);
+ when(mQsController.getExpanded()).thenReturn(true);
+
+ // WHEN
+ int transitionDistance = mNotificationPanelViewController
+ .getMaxPanelTransitionDistance() / 2;
+ mNotificationPanelViewController.setExpandedHeight(transitionDistance);
+
+ // THEN
+ // We are interested in the last value of the stack alpha.
+ ArgumentCaptor<Float> alphaCaptor = ArgumentCaptor.forClass(Float.class);
+ verify(mNotificationStackScrollLayoutController, atLeastOnce())
+ .setAlpha(alphaCaptor.capture());
+ assertThat(alphaCaptor.getValue()).isEqualTo(0.0f);
+ }
+
+ @Test
public void testSwitchesToBigClockInSplitShadeOnAodAnimateDisabled() {
when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false);
mStatusBarStateController.setState(KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index af40e5b..2a9b403 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -27,6 +27,7 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dock.DockManager
@@ -48,6 +49,7 @@
import com.android.systemui.multishade.data.repository.MultiShadeRepository
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor
import com.android.systemui.multishade.domain.interactor.MultiShadeMotionEventInteractor
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -91,6 +93,8 @@
@Mock private lateinit var view: NotificationShadeWindowView
@Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
@Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var backActionInteractor: BackActionInteractor
+ @Mock private lateinit var powerInteractor: PowerInteractor
@Mock private lateinit var dockManager: DockManager
@Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
@Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@@ -171,6 +175,8 @@
statusBarWindowStateController,
lockIconViewController,
centralSurfaces,
+ backActionInteractor,
+ powerInteractor,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
keyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index d3ecc3d..252a03b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -27,6 +27,7 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
@@ -47,6 +48,7 @@
import com.android.systemui.multishade.data.repository.MultiShadeRepository
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor
import com.android.systemui.multishade.domain.interactor.MultiShadeMotionEventInteractor
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -93,6 +95,8 @@
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock private lateinit var shadeController: ShadeController
@Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var backActionInteractor: BackActionInteractor
+ @Mock private lateinit var powerInteractor: PowerInteractor
@Mock private lateinit var dockManager: DockManager
@Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
@Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout
@@ -184,6 +188,8 @@
statusBarWindowStateController,
lockIconViewController,
centralSurfaces,
+ backActionInteractor,
+ powerInteractor,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
keyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
new file mode 100644
index 0000000..8bb8f62
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shade
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.QSFragment
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationsQuickSettingsContainerTest : SysuiTestCase() {
+
+ @Mock private lateinit var qsFrame: View
+ @Mock private lateinit var stackScroller: View
+ @Mock private lateinit var keyguardStatusBar: View
+ @Mock private lateinit var qsFragment: QSFragment
+
+ private lateinit var qsView: ViewGroup
+ private lateinit var qsContainer: View
+
+ private lateinit var underTest: NotificationsQuickSettingsContainer
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = NotificationsQuickSettingsContainer(context, null)
+
+ setUpViews()
+ underTest.onFinishInflate()
+ underTest.onFragmentViewCreated("QS", qsFragment)
+ }
+
+ @Test
+ fun qsContainerPaddingSetAgainAfterQsRecreated() {
+ val padding = 100
+ underTest.setQSContainerPaddingBottom(padding)
+
+ assertThat(qsContainer.paddingBottom).isEqualTo(padding)
+
+ // We reset the padding before "creating" a new QSFragment
+ qsContainer.setPadding(0, 0, 0, 0)
+ underTest.onFragmentViewCreated("QS", qsFragment)
+
+ assertThat(qsContainer.paddingBottom).isEqualTo(padding)
+ }
+
+ private fun setUpViews() {
+ qsView = FrameLayout(context)
+ qsContainer = View(context)
+ qsContainer.id = R.id.quick_settings_container
+ qsView.addView(qsContainer)
+
+ whenever(qsFrame.findViewById<View>(R.id.qs_frame)).thenReturn(qsFrame)
+ whenever(stackScroller.findViewById<View>(R.id.notification_stack_scroller))
+ .thenReturn(stackScroller)
+ whenever(keyguardStatusBar.findViewById<View>(R.id.keyguard_header))
+ .thenReturn(keyguardStatusBar)
+ whenever(qsFragment.view).thenReturn(qsView)
+
+ val layoutParams = ConstraintLayout.LayoutParams(0, 0)
+ whenever(qsFrame.layoutParams).thenReturn(layoutParams)
+ whenever(stackScroller.layoutParams).thenReturn(layoutParams)
+ whenever(keyguardStatusBar.layoutParams).thenReturn(layoutParams)
+
+ underTest.addView(qsFrame)
+ underTest.addView(stackScroller)
+ underTest.addView(keyguardStatusBar)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index f1d56f9..a4fab1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -54,8 +54,6 @@
@SmallTest
class PulsingGestureListenerTest : SysuiTestCase() {
@Mock
- private lateinit var view: NotificationShadeWindowView
- @Mock
private lateinit var dockManager: DockManager
@Mock
private lateinit var falsingManager: FalsingManager
@@ -87,7 +85,6 @@
powerRepository = FakePowerRepository()
underTest = PulsingGestureListener(
- view,
falsingManager,
dockManager,
PowerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
new file mode 100644
index 0000000..c72f4e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shade;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardStatusView;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.TestScopeProvider;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
+import com.android.systemui.media.controls.pipeline.MediaDataManager;
+import com.android.systemui.media.controls.ui.MediaHierarchyManager;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shade.transition.ShadeTransitionController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.QsFrameTranslateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
+import com.android.systemui.statusbar.notification.stack.AmbientState;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.user.domain.interactor.UserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
+
+import dagger.Lazy;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import kotlinx.coroutines.test.TestScope;
+
+public class QuickSettingsControllerBaseTest extends SysuiTestCase {
+ protected static final float QS_FRAME_START_X = 0f;
+ protected static final int QS_FRAME_WIDTH = 1000;
+ protected static final int QS_FRAME_TOP = 0;
+ protected static final int QS_FRAME_BOTTOM = 1000;
+ protected static final int DEFAULT_HEIGHT = 1000;
+ // In split shade min = max
+ protected static final int DEFAULT_MIN_HEIGHT_SPLIT_SHADE = DEFAULT_HEIGHT;
+ protected static final int DEFAULT_MIN_HEIGHT = 300;
+
+ protected QuickSettingsController mQsController;
+
+ protected TestScope mTestScope = TestScopeProvider.getTestScope();
+
+ @Mock
+ protected Resources mResources;
+ @Mock protected KeyguardBottomAreaView mQsFrame;
+ @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
+ @Mock protected QS mQs;
+ @Mock protected QSFragment mQSFragment;
+ @Mock protected Lazy<NotificationPanelViewController> mPanelViewControllerLazy;
+ @Mock protected NotificationPanelViewController mNotificationPanelViewController;
+ @Mock protected NotificationPanelView mPanelView;
+ @Mock protected ViewGroup mQsHeader;
+ @Mock protected ViewParent mPanelViewParent;
+ @Mock protected QsFrameTranslateController mQsFrameTranslateController;
+ @Mock protected ShadeTransitionController mShadeTransitionController;
+ @Mock protected PulseExpansionHandler mPulseExpansionHandler;
+ @Mock protected NotificationRemoteInputManager mNotificationRemoteInputManager;
+ @Mock protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock protected LightBarController mLightBarController;
+ @Mock protected NotificationStackScrollLayoutController
+ mNotificationStackScrollLayoutController;
+ @Mock protected LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
+ @Mock protected ShadeHeaderController mShadeHeaderController;
+ @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ @Mock protected KeyguardStateController mKeyguardStateController;
+ @Mock protected KeyguardBypassController mKeyguardBypassController;
+ @Mock protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock protected ScrimController mScrimController;
+ @Mock protected MediaDataManager mMediaDataManager;
+ @Mock protected MediaHierarchyManager mMediaHierarchyManager;
+ @Mock protected AmbientState mAmbientState;
+ @Mock protected RecordingController mRecordingController;
+ @Mock protected FalsingManager mFalsingManager;
+ @Mock protected FalsingCollector mFalsingCollector;
+ @Mock protected AccessibilityManager mAccessibilityManager;
+ @Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
+ @Mock protected MetricsLogger mMetricsLogger;
+ @Mock protected FeatureFlags mFeatureFlags;
+ @Mock protected InteractionJankMonitor mInteractionJankMonitor;
+ @Mock protected ShadeLogger mShadeLogger;
+ @Mock protected DumpManager mDumpManager;
+ @Mock protected UiEventLogger mUiEventLogger;
+ @Mock protected CastController mCastController;
+ @Mock protected DeviceProvisionedController mDeviceProvisionedController;
+ @Mock protected UserInteractor mUserInteractor;
+ protected FakeDisableFlagsRepository mDisableFlagsRepository =
+ new FakeDisableFlagsRepository();
+ protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
+
+ protected SysuiStatusBarStateController mStatusBarStateController;
+ protected ShadeInteractor mShadeInteractor;
+
+ protected Handler mMainHandler;
+ protected LockscreenShadeTransitionController.Callback mLockscreenShadeTransitionCallback;
+
+ protected final ShadeExpansionStateManager mShadeExpansionStateManager =
+ new ShadeExpansionStateManager();
+
+ protected FragmentHostManager.FragmentListener mFragmentListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mPanelViewControllerLazy.get()).thenReturn(mNotificationPanelViewController);
+ mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
+ mInteractionJankMonitor, mShadeExpansionStateManager);
+
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
+ mShadeInteractor =
+ new ShadeInteractor(
+ mDisableFlagsRepository,
+ mKeyguardRepository,
+ new FakeUserSetupRepository(),
+ mDeviceProvisionedController,
+ mUserInteractor
+ );
+
+ KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
+ keyguardStatusView.setId(R.id.keyguard_status_view);
+
+ when(mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_qs_transition_distance)).thenReturn(DEFAULT_HEIGHT);
+ when(mPanelView.getResources()).thenReturn(mResources);
+ when(mPanelView.getContext()).thenReturn(getContext());
+ when(mPanelView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
+ when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
+ when(mPanelView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
+ when(mQsFrame.getX()).thenReturn(QS_FRAME_START_X);
+ when(mQsFrame.getWidth()).thenReturn(QS_FRAME_WIDTH);
+ when(mQsHeader.getTop()).thenReturn(QS_FRAME_TOP);
+ when(mQsHeader.getBottom()).thenReturn(QS_FRAME_BOTTOM);
+ when(mPanelView.getY()).thenReturn((float) QS_FRAME_TOP);
+ when(mPanelView.getHeight()).thenReturn(QS_FRAME_BOTTOM);
+ when(mPanelView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
+ when(mQs.getView()).thenReturn(mPanelView);
+ when(mQSFragment.getView()).thenReturn(mPanelView);
+
+ when(mNotificationRemoteInputManager.isRemoteInputActive())
+ .thenReturn(false);
+ when(mInteractionJankMonitor.begin(any(), anyInt()))
+ .thenReturn(true);
+ when(mInteractionJankMonitor.end(anyInt()))
+ .thenReturn(true);
+
+ when(mPanelView.getParent()).thenReturn(mPanelViewParent);
+ when(mQs.getHeader()).thenReturn(mQsHeader);
+
+ doAnswer(invocation -> {
+ mLockscreenShadeTransitionCallback = invocation.getArgument(0);
+ return null;
+ }).when(mLockscreenShadeTransitionController).addCallback(any());
+
+
+ mMainHandler = new Handler(Looper.getMainLooper());
+
+ mQsController = new QuickSettingsController(
+ mPanelViewControllerLazy,
+ mPanelView,
+ mQsFrameTranslateController,
+ mShadeTransitionController,
+ mPulseExpansionHandler,
+ mNotificationRemoteInputManager,
+ mShadeExpansionStateManager,
+ mStatusBarKeyguardViewManager,
+ mLightBarController,
+ mNotificationStackScrollLayoutController,
+ mLockscreenShadeTransitionController,
+ mNotificationShadeDepthController,
+ mShadeHeaderController,
+ mStatusBarTouchableRegionManager,
+ mKeyguardStateController,
+ mKeyguardBypassController,
+ mKeyguardUpdateMonitor,
+ mScrimController,
+ mMediaDataManager,
+ mMediaHierarchyManager,
+ mAmbientState,
+ mRecordingController,
+ mFalsingManager,
+ mFalsingCollector,
+ mAccessibilityManager,
+ mLockscreenGestureLogger,
+ mMetricsLogger,
+ mFeatureFlags,
+ mInteractionJankMonitor,
+ mShadeLogger,
+ mDumpManager,
+ mock(KeyguardFaceAuthInteractor.class),
+ mock(ShadeRepository.class),
+ mShadeInteractor,
+ new JavaAdapter(mTestScope.getBackgroundScope()),
+ mCastController
+ );
+ mQsController.init();
+
+ mFragmentListener = mQsController.getQsFragmentListener();
+ }
+
+ @After
+ public void tearDown() {
+ mMainHandler.removeCallbacksAndMessages(null);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index ff047aa..6d288e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -28,238 +28,32 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.keyguard.KeyguardStatusView;
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
-import com.android.systemui.media.controls.pipeline.MediaDataManager;
-import com.android.systemui.media.controls.ui.MediaHierarchyManager;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.qs.QSFragment;
-import com.android.systemui.screenrecord.RecordingController;
-import com.android.systemui.shade.data.repository.ShadeRepository;
-import com.android.systemui.shade.transition.ShadeTransitionController;
-import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.QsFrameTranslateController;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.stack.AmbientState;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
-import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import dagger.Lazy;
-
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class QuickSettingsControllerTest extends SysuiTestCase {
-
- private static final float QS_FRAME_START_X = 0f;
- private static final int QS_FRAME_WIDTH = 1000;
- private static final int QS_FRAME_TOP = 0;
- private static final int QS_FRAME_BOTTOM = 1000;
- private static final int DEFAULT_HEIGHT = 1000;
- // In split shade min = max
- private static final int DEFAULT_MIN_HEIGHT_SPLIT_SHADE = DEFAULT_HEIGHT;
- private static final int DEFAULT_MIN_HEIGHT = 300;
-
- private QuickSettingsController mQsController;
-
- @Mock private Resources mResources;
- @Mock private KeyguardBottomAreaView mQsFrame;
- @Mock private KeyguardStatusBarView mKeyguardStatusBar;
- @Mock private QS mQs;
- @Mock private QSFragment mQSFragment;
- @Mock private Lazy<NotificationPanelViewController> mPanelViewControllerLazy;
- @Mock private NotificationPanelViewController mNotificationPanelViewController;
- @Mock private NotificationPanelView mPanelView;
- @Mock private ViewGroup mQsHeader;
- @Mock private ViewParent mPanelViewParent;
- @Mock private QsFrameTranslateController mQsFrameTranslateController;
- @Mock private ShadeTransitionController mShadeTransitionController;
- @Mock private PulseExpansionHandler mPulseExpansionHandler;
- @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
- @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock private LightBarController mLightBarController;
- @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
- @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
- @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
- @Mock private ShadeHeaderController mShadeHeaderController;
- @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
- @Mock private KeyguardStateController mKeyguardStateController;
- @Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock private ScrimController mScrimController;
- @Mock private MediaDataManager mMediaDataManager;
- @Mock private MediaHierarchyManager mMediaHierarchyManager;
- @Mock private AmbientState mAmbientState;
- @Mock private RecordingController mRecordingController;
- @Mock private FalsingManager mFalsingManager;
- @Mock private FalsingCollector mFalsingCollector;
- @Mock private AccessibilityManager mAccessibilityManager;
- @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
- @Mock private MetricsLogger mMetricsLogger;
- @Mock private FeatureFlags mFeatureFlags;
- @Mock private InteractionJankMonitor mInteractionJankMonitor;
- @Mock private ShadeLogger mShadeLogger;
- @Mock private DumpManager mDumpManager;
- @Mock private UiEventLogger mUiEventLogger;
- @Mock private CastController mCastController;
-
- private SysuiStatusBarStateController mStatusBarStateController;
-
- private Handler mMainHandler;
- private LockscreenShadeTransitionController.Callback mLockscreenShadeTransitionCallback;
-
- private final ShadeExpansionStateManager mShadeExpansionStateManager =
- new ShadeExpansionStateManager();
-
- private FragmentHostManager.FragmentListener mFragmentListener;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mPanelViewControllerLazy.get()).thenReturn(mNotificationPanelViewController);
- mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
- mInteractionJankMonitor, mShadeExpansionStateManager);
-
- KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
- keyguardStatusView.setId(R.id.keyguard_status_view);
-
- when(mResources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_qs_transition_distance)).thenReturn(DEFAULT_HEIGHT);
- when(mPanelView.getResources()).thenReturn(mResources);
- when(mPanelView.getContext()).thenReturn(getContext());
- when(mPanelView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
- when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
- when(mPanelView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
- when(mQsFrame.getX()).thenReturn(QS_FRAME_START_X);
- when(mQsFrame.getWidth()).thenReturn(QS_FRAME_WIDTH);
- when(mQsHeader.getTop()).thenReturn(QS_FRAME_TOP);
- when(mQsHeader.getBottom()).thenReturn(QS_FRAME_BOTTOM);
- when(mPanelView.getY()).thenReturn((float) QS_FRAME_TOP);
- when(mPanelView.getHeight()).thenReturn(QS_FRAME_BOTTOM);
- when(mPanelView.findViewById(R.id.keyguard_status_view))
- .thenReturn(mock(KeyguardStatusView.class));
- when(mQs.getView()).thenReturn(mPanelView);
- when(mQSFragment.getView()).thenReturn(mPanelView);
-
- when(mNotificationRemoteInputManager.isRemoteInputActive())
- .thenReturn(false);
- when(mInteractionJankMonitor.begin(any(), anyInt()))
- .thenReturn(true);
- when(mInteractionJankMonitor.end(anyInt()))
- .thenReturn(true);
-
- when(mPanelView.getParent()).thenReturn(mPanelViewParent);
- when(mQs.getHeader()).thenReturn(mQsHeader);
-
- doAnswer(invocation -> {
- mLockscreenShadeTransitionCallback = invocation.getArgument(0);
- return null;
- }).when(mLockscreenShadeTransitionController).addCallback(any());
-
-
- mMainHandler = new Handler(Looper.getMainLooper());
-
- mQsController = new QuickSettingsController(
- mPanelViewControllerLazy,
- mPanelView,
- mQsFrameTranslateController,
- mShadeTransitionController,
- mPulseExpansionHandler,
- mNotificationRemoteInputManager,
- mShadeExpansionStateManager,
- mStatusBarKeyguardViewManager,
- mLightBarController,
- mNotificationStackScrollLayoutController,
- mLockscreenShadeTransitionController,
- mNotificationShadeDepthController,
- mShadeHeaderController,
- mStatusBarTouchableRegionManager,
- mKeyguardStateController,
- mKeyguardBypassController,
- mKeyguardUpdateMonitor,
- mScrimController,
- mMediaDataManager,
- mMediaHierarchyManager,
- mAmbientState,
- mRecordingController,
- mFalsingManager,
- mFalsingCollector,
- mAccessibilityManager,
- mLockscreenGestureLogger,
- mMetricsLogger,
- mFeatureFlags,
- mInteractionJankMonitor,
- mShadeLogger,
- mDumpManager,
- mock(KeyguardFaceAuthInteractor.class),
- mock(ShadeRepository.class),
- mCastController
- );
-
- mFragmentListener = mQsController.getQsFragmentListener();
- }
-
- @After
- public void tearDown() {
- mMainHandler.removeCallbacksAndMessages(null);
- }
+public class QuickSettingsControllerTest extends QuickSettingsControllerBaseTest {
@Test
public void testCloseQsSideEffects() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerWithCoroutinesTest.kt
new file mode 100644
index 0000000..cc4a063
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerWithCoroutinesTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shade
+
+import android.app.StatusBarManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class QuickSettingsControllerWithCoroutinesTest : QuickSettingsControllerBaseTest() {
+
+ @Test
+ fun isExpansionEnabled_dozing_false() =
+ mTestScope.runTest {
+ mKeyguardRepository.setIsDozing(true)
+ runCurrent()
+
+ assertThat(mQsController.isExpansionEnabled).isFalse()
+ }
+
+ @Test
+ fun isExpansionEnabled_notDozing_true() =
+ mTestScope.runTest {
+ mKeyguardRepository.setIsDozing(false)
+ runCurrent()
+
+ assertThat(mQsController.isExpansionEnabled).isTrue()
+ }
+
+ @Test
+ fun isExpansionEnabled_qsDisabled_false() =
+ mTestScope.runTest {
+ mDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_QUICK_SETTINGS
+ )
+ runCurrent()
+
+ assertThat(mQsController.isExpansionEnabled).isFalse()
+ }
+
+ @Test
+ fun isExpansionEnabled_shadeDisabled_false() =
+ mTestScope.runTest {
+ mDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+ )
+ runCurrent()
+
+ assertThat(mQsController.isExpansionEnabled).isFalse()
+ }
+
+ @Test
+ fun isExpansionEnabled_qsAndShadeEnabled_true() =
+ mTestScope.runTest {
+ mDisableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE)
+ runCurrent()
+
+ assertThat(mQsController.isExpansionEnabled).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 57ae621..31bfa3fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -66,6 +66,11 @@
@SmallTest
public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
+ private static final String SINGLE_CARRIER_TEXT = "singleCarrierText";
+ private static final String MULTI_CARRIER_TEXT = "multiCarrierText";
+ private static final String FIRST_CARRIER_NAME = "carrier1";
+ private static final String SECOND_CARRIER_NAME = "carrier2";
+
private ShadeCarrierGroupController mShadeCarrierGroupController;
private SignalCallback mSignalCallback;
private CarrierTextManager.CarrierTextCallback mCallback;
@@ -148,8 +153,8 @@
// listOfCarriers length 1, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
false,
new int[]{0});
mCallback.updateCarrierInfo(c1);
@@ -157,8 +162,8 @@
// listOfCarriers length 1, subscriptionIds length 1, anySims true
CarrierTextManager.CarrierTextCallbackInfo
c2 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
true,
new int[]{0});
mCallback.updateCarrierInfo(c2);
@@ -166,8 +171,8 @@
// listOfCarriers length 2, subscriptionIds length 2, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c3 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
false,
new int[]{0, 1});
mCallback.updateCarrierInfo(c3);
@@ -175,8 +180,8 @@
// listOfCarriers length 2, subscriptionIds length 2, anySims true
CarrierTextManager.CarrierTextCallbackInfo
c4 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0, 1});
mCallback.updateCarrierInfo(c4);
@@ -189,8 +194,8 @@
// listOfCarriers length 2, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
false,
new int[]{0});
mCallback.updateCarrierInfo(c1);
@@ -198,8 +203,8 @@
// listOfCarriers length 2, subscriptionIds length 1, anySims true
CarrierTextManager.CarrierTextCallbackInfo
c2 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0});
mCallback.updateCarrierInfo(c2);
@@ -207,8 +212,8 @@
// listOfCarriers length 1, subscriptionIds length 2, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c3 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
false,
new int[]{0, 1});
mCallback.updateCarrierInfo(c3);
@@ -216,8 +221,8 @@
// listOfCarriers length 1, subscriptionIds length 2, anySims true
CarrierTextManager.CarrierTextCallbackInfo
c4 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
true,
new int[]{0, 1});
mCallback.updateCarrierInfo(c4);
@@ -230,8 +235,8 @@
CarrierTextManager.CarrierTextCallbackInfo
c4 = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0, 1});
mCallback.updateCarrierInfo(c4);
@@ -264,6 +269,20 @@
}
@Test
+ public void testVisibleView_airplaneMode_WFCOn() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ info = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{FIRST_CARRIER_NAME, ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+ mCallback.updateCarrierInfo(info);
+ mTestableLooper.processAllMessages();
+ assertEquals(View.VISIBLE, mShadeCarrierGroupController.getShadeCarrierVisibility(0));
+ }
+
+ @Test
public void testListenerNotCalledOnRegistreation() {
mShadeCarrierGroupController
.setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
@@ -276,8 +295,8 @@
// Only one element in the info
CarrierTextManager.CarrierTextCallbackInfo
info = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{SINGLE_CARRIER_TEXT},
true,
new int[]{0},
false /* airplaneMode */);
@@ -295,8 +314,8 @@
// More than one element in the info
CarrierTextManager.CarrierTextCallbackInfo
info = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0, 1},
false /* airplaneMode */);
@@ -313,16 +332,16 @@
public void testSingleMultiCarrierSwitch() {
CarrierTextManager.CarrierTextCallbackInfo
singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
true,
new int[]{0},
false /* airplaneMode */);
CarrierTextManager.CarrierTextCallbackInfo
multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0, 1},
false /* airplaneMode */);
@@ -347,8 +366,8 @@
public void testNoCallbackIfSingleCarrierDoesntChange() {
CarrierTextManager.CarrierTextCallbackInfo
singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{""},
+ SINGLE_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME},
true,
new int[]{0},
false /* airplaneMode */);
@@ -369,8 +388,8 @@
public void testNoCallbackIfMultiCarrierDoesntChange() {
CarrierTextManager.CarrierTextCallbackInfo
multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
- "",
- new CharSequence[]{"", ""},
+ MULTI_CARRIER_TEXT,
+ new CharSequence[]{FIRST_CARRIER_NAME, SECOND_CARRIER_NAME},
true,
new int[]{0, 1},
false /* airplaneMode */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
new file mode 100644
index 0000000..7392a94
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shade.data.repository
+
+import android.app.ActivityManager
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.os.UserManager
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
+import com.android.systemui.user.data.model.UserSwitcherSettingsModel
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
+import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class ShadeInteractorTest : SysuiTestCase() {
+ private lateinit var underTest: ShadeInteractor
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+ private val featureFlags = FakeFeatureFlags()
+ private val userSetupRepository = FakeUserSetupRepository()
+ private val userRepository = FakeUserRepository()
+ private val disableFlagsRepository = FakeDisableFlagsRepository()
+ private val keyguardRepository = FakeKeyguardRepository()
+
+ @Mock private lateinit var manager: UserManager
+ @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var activityManager: ActivityManager
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var guestInteractor: GuestUserInteractor
+
+ private lateinit var userInteractor: UserInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
+
+ val refreshUsersScheduler =
+ RefreshUsersScheduler(
+ applicationScope = testScope.backgroundScope,
+ mainDispatcher = testDispatcher,
+ repository = userRepository,
+ )
+ userInteractor =
+ UserInteractor(
+ applicationContext = context,
+ repository = userRepository,
+ activityStarter = activityStarter,
+ keyguardInteractor =
+ KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ .keyguardInteractor,
+ featureFlags = featureFlags,
+ manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
+ applicationScope = testScope.backgroundScope,
+ telephonyInteractor =
+ TelephonyInteractor(
+ repository = FakeTelephonyRepository(),
+ ),
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ backgroundDispatcher = testDispatcher,
+ activityManager = activityManager,
+ refreshUsersScheduler = refreshUsersScheduler,
+ guestUserInteractor = guestInteractor,
+ uiEventLogger = uiEventLogger,
+ )
+ underTest =
+ ShadeInteractor(
+ disableFlagsRepository,
+ keyguardRepository,
+ userSetupRepository,
+ deviceProvisionedController,
+ userInteractor,
+ )
+ }
+
+ @Test
+ fun isExpandToQsEnabled_deviceNotProvisioned_false() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+
+ userSetupRepository.setUserSetup(false)
+ userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_shadeNotEnabled_false() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ userSetupRepository.setUserSetup(true)
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NOTIFICATION_SHADE,
+ )
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ userSetupRepository.setUserSetup(true)
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_QUICK_SETTINGS,
+ )
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_dozing_false() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ userSetupRepository.setUserSetup(true)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+
+ keyguardRepository.setIsDozing(true)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_userSetup_true() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ keyguardRepository.setIsDozing(false)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+
+ userSetupRepository.setUserSetup(true)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ keyguardRepository.setIsDozing(false)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+
+ userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = false))
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_respondsToDozingUpdates() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ keyguardRepository.setIsDozing(false)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+ userSetupRepository.setUserSetup(true)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isTrue()
+
+ // WHEN dozing starts
+ keyguardRepository.setIsDozing(true)
+
+ // THEN expand is disabled
+ assertThat(actual).isFalse()
+
+ // WHEN dozing stops
+ keyguardRepository.setIsDozing(false)
+
+ // THEN expand is enabled
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_respondsToDisableUpdates() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ keyguardRepository.setIsDozing(false)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+ userSetupRepository.setUserSetup(true)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isTrue()
+
+ // WHEN QS is disabled
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_QUICK_SETTINGS,
+ )
+ // THEN expand is disabled
+ assertThat(actual).isFalse()
+
+ // WHEN QS is enabled
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+ // THEN expand is enabled
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isExpandToQsEnabled_respondsToUserUpdates() =
+ testScope.runTest {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ keyguardRepository.setIsDozing(false)
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(
+ disable2 = DISABLE2_NONE,
+ )
+ userSetupRepository.setUserSetup(true)
+
+ val actual by collectLastValue(underTest.isExpandToQsEnabled)
+
+ assertThat(actual).isTrue()
+
+ // WHEN the user is no longer setup
+ userSetupRepository.setUserSetup(false)
+ userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
+
+ // THEN expand is disabled
+ assertThat(actual).isFalse()
+
+ // WHEN the user is setup again
+ userSetupRepository.setUserSetup(true)
+
+ // THEN expand is enabled
+ assertThat(actual).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 04c93cb..9495fdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -21,6 +21,8 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags.TRANSIT_CLOCK
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
@@ -68,6 +70,7 @@
private lateinit var fakeDefaultProvider: FakeClockPlugin
private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
private lateinit var registry: ClockRegistry
+ private val featureFlags = FakeFeatureFlags()
companion object {
private fun failFactory(clockId: ClockId): ClockController {
@@ -448,4 +451,44 @@
val actual = ClockSettings.serialize(ClockSettings("ID", null))
assertEquals(expected, actual)
}
+
+ @Test
+ fun testTransitClockEnabled_hasTransitClock() {
+ testTransitClockFlag(true)
+ }
+
+ @Test
+ fun testTransitClockDisabled_noTransitClock() {
+ testTransitClockFlag(false)
+ }
+
+ private fun testTransitClockFlag(flag: Boolean) {
+ featureFlags.set(TRANSIT_CLOCK, flag)
+ registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK)
+ val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>()
+ val plugin = FakeClockPlugin()
+ .addClock("clock_1", "clock 1")
+ .addClock("DIGITAL_CLOCK_METRO", "metro clock")
+ pluginListener.onPluginLoaded(plugin, mockContext, mockPluginLifecycle)
+
+ val list = registry.getClocks()
+ if (flag) {
+ assertEquals(
+ setOf(
+ ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
+ ClockMetadata("clock_1", "clock 1"),
+ ClockMetadata("DIGITAL_CLOCK_METRO", "metro clock")
+ ),
+ list.toSet()
+ )
+ } else {
+ assertEquals(
+ setOf(
+ ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
+ ClockMetadata("clock_1", "clock 1")
+ ),
+ list.toSet()
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 1643e17..385d556 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -16,7 +16,6 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
-import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
@@ -201,7 +200,7 @@
mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(IME_INVISIBLE),
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(0),
eq(BACK_DISPOSITION_DEFAULT), eq(false));
verify(mCallbacks).setImeWindowStatus(
eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 2d5ff24..25efea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -26,6 +26,7 @@
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
+import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -100,6 +101,7 @@
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -287,6 +289,8 @@
Looper.prepare();
}
+ FakeFeatureFlags flags = new FakeFeatureFlags();
+ flags.set(KEYGUARD_TALKBACK_FIX, true);
mController = new KeyguardIndicationController(
mContext,
mTestableLooper.getLooper(),
@@ -300,7 +304,8 @@
mAlternateBouncerInteractor,
mAlarmManager,
mUserTracker,
- mock(BouncerMessageInteractor.class)
+ mock(BouncerMessageInteractor.class),
+ flags
);
mController.init();
mController.setIndicationArea(mIndicationArea);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 2351f760..21e0f68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -8,12 +8,15 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.media.controls.ui.MediaHierarchyManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -26,6 +29,7 @@
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.android.systemui.util.mockito.mock
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@@ -83,6 +87,12 @@
@Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
@Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
+ private val powerInteractor = PowerInteractor(
+ FakePowerRepository(),
+ FalsingCollectorFake(),
+ screenOffAnimationController = mock(),
+ statusBarStateController = mock(),
+ )
@JvmField @Rule val mockito = MockitoJUnit.rule()
private val configurationController = FakeConfigurationController()
@@ -129,6 +139,7 @@
qsTransitionControllerFactory = { qsTransitionController },
activityStarter = activityStarter,
shadeRepository = FakeShadeRepository(),
+ powerInteractor = powerInteractor,
)
transitionController.addCallback(transitionControllerCallback)
whenever(nsslController.view).thenReturn(stackscroller)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index ced0734..305f48b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -33,25 +33,21 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.RemoteInputControllerLogger;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
-import dagger.Lazy;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -69,6 +65,7 @@
@Mock private RemoteInputUriController mRemoteInputUriController;
@Mock private NotificationClickNotifier mClickNotifier;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock private PowerInteractor mPowerInteractor;
private TestableNotificationRemoteInputManager mRemoteInputManager;
private NotificationEntry mEntry;
@@ -82,7 +79,7 @@
mLockscreenUserManager,
mSmartReplyController,
mVisibilityProvider,
- () -> Optional.of(mock(CentralSurfaces.class)),
+ mPowerInteractor,
mStateController,
mRemoteInputUriController,
mock(RemoteInputControllerLogger.class),
@@ -140,7 +137,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationVisibilityProvider visibilityProvider,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
+ PowerInteractor powerInteractor,
StatusBarStateController statusBarStateController,
RemoteInputUriController remoteInputUriController,
RemoteInputControllerLogger remoteInputControllerLogger,
@@ -153,7 +150,7 @@
lockscreenUserManager,
smartReplyController,
visibilityProvider,
- centralSurfacesOptionalLazy,
+ powerInteractor,
statusBarStateController,
remoteInputUriController,
remoteInputControllerLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
index 4b5d0a3..f1c7956 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
@@ -37,73 +37,8 @@
private val disableFlagsLogger = DisableFlagsLogger(disable1Flags, disable2Flags)
@Test
- fun getDisableFlagsString_oldAndNewSame_newAndUnchangedLoggedOldNotLogged() {
- val state = DisableFlagsLogger.DisableState(
- 0b111, // ABC
- 0b01 // mN
- )
-
- val result = disableFlagsLogger.getDisableFlagsString(state, state)
-
- assertThat(result).doesNotContain("Old")
- assertThat(result).contains("ABC.mN")
- assertThat(result).contains("(unchanged)")
- }
-
- @Test
- fun getDisableFlagsString_oldAndNewDifferent_statesAndDiffLogged() {
- val result = disableFlagsLogger.getDisableFlagsString(
- DisableFlagsLogger.DisableState(
- 0b111, // ABC
- 0b01, // mN
- ),
- DisableFlagsLogger.DisableState(
- 0b001, // abC
- 0b10 // Mn
- )
- )
-
- assertThat(result).contains("Old: ABC.mN")
- assertThat(result).contains("New: abC.Mn")
- assertThat(result).contains("(changed: ab.Mn)")
- }
-
- @Test
- fun getDisableFlagsString_onlyDisable2Different_diffLoggedCorrectly() {
- val result = disableFlagsLogger.getDisableFlagsString(
- DisableFlagsLogger.DisableState(
- 0b001, // abC
- 0b01, // mN
- ),
- DisableFlagsLogger.DisableState(
- 0b001, // abC
- 0b00 // mn
- )
- )
-
- assertThat(result).contains("(changed: .n)")
- }
-
- @Test
- fun getDisableFlagsString_nullOld_onlyNewStateLogged() {
- val result = disableFlagsLogger.getDisableFlagsString(
- old = null,
- new = DisableFlagsLogger.DisableState(
- 0b001, // abC
- 0b01, // mN
- ),
- )
-
- assertThat(result).doesNotContain("Old")
- assertThat(result).contains("abC.mN")
- assertThat(result).doesNotContain("(")
- assertThat(result).doesNotContain(")")
- }
-
- @Test
fun getDisableFlagsString_nullLocalModification_localModNotLogged() {
val result = disableFlagsLogger.getDisableFlagsString(
- DisableFlagsLogger.DisableState(0, 0),
DisableFlagsLogger.DisableState(1, 1),
newAfterLocalModification = null
)
@@ -118,9 +53,7 @@
0b10 // mn
)
- val result = disableFlagsLogger.getDisableFlagsString(
- DisableFlagsLogger.DisableState(0, 0), newState, newState
- )
+ val result = disableFlagsLogger.getDisableFlagsString(newState, newState)
assertThat(result).doesNotContain("local modification")
}
@@ -128,7 +61,6 @@
@Test
fun getDisableFlagsString_newAfterLocalModificationDifferent_localModAndDiffLogged() {
val result = disableFlagsLogger.getDisableFlagsString(
- old = DisableFlagsLogger.DisableState(0, 0),
new = DisableFlagsLogger.DisableState(
0b000, // abc
0b00 // mn
@@ -143,6 +75,22 @@
}
@Test
+ fun getDisableFlagsString_onlyDisable2Different_diffLoggedCorrectly() {
+ val result = disableFlagsLogger.getDisableFlagsString(
+ DisableFlagsLogger.DisableState(
+ 0b001, // abC
+ 0b01, // mN
+ ),
+ DisableFlagsLogger.DisableState(
+ 0b001, // abC
+ 0b00 // mn
+ )
+ )
+
+ assertThat(result).contains("(changed: .n)")
+ }
+
+ @Test
fun constructor_defaultDisableFlags_noException() {
// Just creating the logger with the default params will trigger the exception if there
// is one.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
new file mode 100644
index 0000000..580463a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.data.repository
+
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_NONE
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+import android.content.res.Configuration
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.verify
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class DisableFlagsRepositoryTest : SysuiTestCase() {
+
+ private lateinit var underTest: DisableFlagsRepository
+
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val commandQueue: CommandQueue = mock()
+ private val configurationController: ConfigurationController = mock()
+ private val remoteInputQuickSettingsDisabler =
+ RemoteInputQuickSettingsDisabler(
+ context,
+ commandQueue,
+ configurationController,
+ )
+ private val logBuffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
+ private val disableFlagsLogger = DisableFlagsLogger()
+
+ @Before
+ fun setUp() {
+ underTest =
+ DisableFlagsRepositoryImpl(
+ commandQueue,
+ DISPLAY_ID,
+ testScope.backgroundScope,
+ remoteInputQuickSettingsDisabler,
+ logBuffer,
+ disableFlagsLogger,
+ )
+ }
+
+ @Test
+ fun disableFlags_initialValue_none() {
+ assertThat(underTest.disableFlags.value)
+ .isEqualTo(DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE))
+ }
+
+ @Test
+ fun disableFlags_noSubscribers_callbackStillRegistered() =
+ testScope.runTest { verify(commandQueue).addCallback(any()) }
+
+ @Test
+ fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_notifAlertsDisabled_notifAlertsEnabledFalse() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isFalse()
+ }
+
+ @Test
+ fun disableFlags_notifAlertsDisabled_differentDisplay_notifAlertsEnabledTrue() =
+ testScope.runTest {
+ val wrongDisplayId = DISPLAY_ID + 10
+
+ getCommandQueueCallback()
+ .disable(
+ wrongDisplayId,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+
+ // THEN our repo reports them as still enabled
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_shadeNotDisabled_shadeEnabledTrue() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isShadeEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_shadeDisabled_shadeEnabledFalse() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NONE,
+ DISABLE2_NOTIFICATION_SHADE,
+ /* animate= */ false,
+ )
+
+ assertThat(underTest.disableFlags.value.isShadeEnabled()).isFalse()
+ }
+
+ @Test
+ fun disableFlags_shadeDisabled_differentDisplay_shadeEnabledTrue() =
+ testScope.runTest {
+ val wrongDisplayId = DISPLAY_ID + 10
+
+ getCommandQueueCallback()
+ .disable(
+ wrongDisplayId,
+ DISABLE_NONE,
+ DISABLE2_NOTIFICATION_SHADE,
+ /* animate= */ false,
+ )
+
+ // THEN our repo reports them as still enabled
+ assertThat(underTest.disableFlags.value.isShadeEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_quickSettingsNotDisabled_quickSettingsEnabledTrue() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_quickSettingsDisabled_quickSettingsEnabledFalse() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NONE,
+ DISABLE2_QUICK_SETTINGS,
+ /* animate= */ false,
+ )
+
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
+ }
+
+ @Test
+ fun disableFlags_quickSettingsDisabled_differentDisplay_quickSettingsEnabledTrue() =
+ testScope.runTest {
+ val wrongDisplayId = DISPLAY_ID + 10
+
+ getCommandQueueCallback()
+ .disable(
+ wrongDisplayId,
+ DISABLE_NONE,
+ DISABLE2_QUICK_SETTINGS,
+ /* animate= */ false,
+ )
+
+ // THEN our repo reports them as still enabled
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_remoteInputActive_quickSettingsEnabledFalse() =
+ testScope.runTest {
+ // WHEN remote input is set up to be active
+ val configuration = Configuration(mContext.resources.configuration)
+ configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_use_split_notification_shade,
+ /* value= */ false
+ )
+ remoteInputQuickSettingsDisabler.setRemoteInputActive(true)
+ remoteInputQuickSettingsDisabler.onConfigChanged(configuration)
+
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NONE,
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+
+ // THEN quick settings is disabled (even if the disable flags don't say so)
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
+ }
+
+ @Test
+ fun disableFlags_reactsToChanges() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isFalse()
+
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_CLOCK, // Unrelated to notifications
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isTrue()
+
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_QUICK_SETTINGS or DISABLE2_NOTIFICATION_SHADE,
+ /* animate= */ false,
+ )
+ assertThat(underTest.disableFlags.value.areNotificationAlertsEnabled()).isFalse()
+ assertThat(underTest.disableFlags.value.isShadeEnabled()).isFalse()
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
+ }
+
+ private fun getCommandQueueCallback(): CommandQueue.Callbacks {
+ val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(callbackCaptor.capture())
+ return callbackCaptor.value
+ }
+
+ private companion object {
+ const val DISPLAY_ID = 1
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
new file mode 100644
index 0000000..b66231c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.data.repository
+
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeDisableFlagsRepository : DisableFlagsRepository {
+ override val disableFlags = MutableStateFlow(DisableFlagsModel())
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index ac66ad9..2d044fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -92,8 +92,9 @@
.getPeopleNotificationType(entry))
.thenReturn(TYPE_PERSON);
- // THEN it has high priority
+ // THEN it has high priority BUT it has low explicit priority.
assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ assertFalse(mHighPriorityProvider.isExplicitlyHighPriority(entry));
}
@Test
@@ -115,7 +116,7 @@
@Test
public void lowImportanceConversation() {
- // GIVEN notification is high importance and is a people notification
+ // GIVEN notification is low importance and is a people notification
final Notification notification = new Notification.Builder(mContext, "test")
.build();
final NotificationEntry entry = new NotificationEntryBuilder()
@@ -162,8 +163,9 @@
.getPeopleNotificationType(entry))
.thenReturn(TYPE_NON_PERSON);
- // THEN it has high priority
+ // THEN it has high priority but low explicit priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
+ assertFalse(mHighPriorityProvider.isExplicitlyHighPriority(entry));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt
new file mode 100644
index 0000000..fe49016
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsInteractorTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.domain.interactor
+
+import android.app.StatusBarManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepositoryImpl
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.verify
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class NotificationsInteractorTest : SysuiTestCase() {
+
+ private lateinit var underTest: NotificationsInteractor
+
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val commandQueue: CommandQueue = mock()
+ private val logBuffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
+ private val disableFlagsLogger = DisableFlagsLogger()
+ private lateinit var disableFlagsRepository: DisableFlagsRepository
+
+ @Before
+ fun setUp() {
+ disableFlagsRepository =
+ DisableFlagsRepositoryImpl(
+ commandQueue,
+ DISPLAY_ID,
+ testScope.backgroundScope,
+ mock(),
+ logBuffer,
+ disableFlagsLogger,
+ )
+ underTest = NotificationsInteractor(disableFlagsRepository)
+ }
+
+ @Test
+ fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() {
+ val callback = getCommandQueueCallback()
+
+ callback.disable(
+ DISPLAY_ID,
+ StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NONE,
+ /* animate= */ false
+ )
+
+ assertThat(underTest.areNotificationAlertsEnabled()).isTrue()
+ }
+
+ @Test
+ fun disableFlags_notifAlertsDisabled_notifAlertsEnabledFalse() {
+ val callback = getCommandQueueCallback()
+
+ callback.disable(
+ DISPLAY_ID,
+ StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
+ StatusBarManager.DISABLE2_NONE,
+ /* animate= */ false
+ )
+
+ assertThat(underTest.areNotificationAlertsEnabled()).isFalse()
+ }
+
+ private fun getCommandQueueCallback(): CommandQueue.Callbacks {
+ val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(callbackCaptor.capture())
+ return callbackCaptor.value
+ }
+
+ private companion object {
+ const val DISPLAY_ID = 1
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 6bd3f7a..8f39ee6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -257,7 +257,7 @@
.setImportance(IMPORTANCE_LOW)
.setParent(parent)
.build();
- when(mHighPriorityProvider.isHighPriority(any())).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@@ -270,7 +270,7 @@
.setUser(new UserHandle(NOTIF_USER_ID))
.setImportance(IMPORTANCE_LOW)
.build();
- when(mHighPriorityProvider.isHighPriority(any())).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@@ -292,7 +292,7 @@
.setImportance(IMPORTANCE_LOW)
.setParent(parent)
.build();
- when(mHighPriorityProvider.isHighPriority(any())).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@@ -309,7 +309,7 @@
mEntry = new NotificationEntryBuilder()
.setImportance(IMPORTANCE_LOW)
.build();
- when(mHighPriorityProvider.isHighPriority(any())).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
@@ -328,7 +328,7 @@
mEntry = new NotificationEntryBuilder()
.setImportance(IMPORTANCE_LOW)
.build();
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(mEntry)).thenReturn(false);
// THEN do not filter out the entry
assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
@@ -345,7 +345,7 @@
.setUser(new UserHandle(NOTIF_USER_ID))
.setImportance(IMPORTANCE_LOW)
.build();
- when(mHighPriorityProvider.isHighPriority(any())).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(any())).thenReturn(false);
// WhHEN the show silent notifs on lockscreen setting is unset
assertNull(mFakeSettings.getString(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS));
@@ -460,13 +460,33 @@
.setKey(mEntry.getKey())
.setImportance(IMPORTANCE_MIN)
.build());
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(mEntry)).thenReturn(false);
// THEN filter out the entry
assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
}
@Test
+ public void highPriorityCharacteristicsIgnored() {
+ // GIVEN an 'unfiltered-keyguard-showing' state with silent notifications hidden
+ setupUnfilteredState(mEntry);
+ mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+ mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+
+ // WHEN the notification doesn't exceed the threshold to show on the lockscreen, but does
+ // have the "high priority characteristics" that would promote it to high priority
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+ when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(mEntry)).thenReturn(false);
+
+ // THEN filter out the entry anyway, because the user explicitly asked us to hide it
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
public void notificationVisibilityPublic() {
// GIVEN a VISIBILITY_PUBLIC notification
NotificationEntryBuilder entryBuilder = new NotificationEntryBuilder()
@@ -538,14 +558,14 @@
// WHEN its parent does exceed threshold tot show on the lockscreen
mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(parent)).thenReturn(true);
// THEN filter out the entry regardless of parent
assertTrue(
mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
// WHEN its parent doesn't exceed threshold to show on lockscreen
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(parent)).thenReturn(false);
modifyEntry(parent.getSummary(), builder -> builder
.setImportance(IMPORTANCE_MIN)
.done());
@@ -591,7 +611,7 @@
// notification doesn't have a summary
// notification is high priority, so it shouldn't be filtered
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
+ when(mHighPriorityProvider.isExplicitlyHighPriority(mEntry)).thenReturn(true);
}
@SysUISingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
new file mode 100644
index 0000000..7707a7e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.statusbar.notification.stack.StackStateLogger
+import com.google.common.truth.Truth
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class StackStateLoggerTest : SysuiTestCase() {
+ private val logBufferCounter = LogBufferCounter()
+ private lateinit var logger: StackStateLogger
+
+ @Before
+ fun setup() {
+ logger = StackStateLogger(logBufferCounter.logBuffer, logBufferCounter.logBuffer)
+ }
+
+ @Test
+ fun groupChildRemovalEvent() {
+ logger.groupChildRemovalEventProcessed(KEY)
+ verifyDidLog(1)
+ logger.groupChildRemovalAnimationEnded(KEY)
+ verifyDidLog(1)
+ }
+
+ class LogBufferCounter {
+ val recentLogs = mutableListOf<Pair<String, LogLevel>>()
+ val tracker =
+ object : LogcatEchoTracker {
+ override val logInBackgroundThread: Boolean = false
+ override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = false
+ override fun isTagLoggable(tagName: String, level: LogLevel): Boolean {
+ recentLogs.add(tagName to level)
+ return true
+ }
+ }
+ val logBuffer =
+ LogBuffer(name = "test", maxSize = 1, logcatEchoTracker = tracker, systrace = false)
+
+ fun verifyDidLog(times: Int) {
+ Truth.assertThat(recentLogs).hasSize(times)
+ recentLogs.clear()
+ }
+ }
+
+ private fun verifyDidLog(times: Int) {
+ logBufferCounter.verifyDidLog(times)
+ }
+
+ companion object {
+ private val KEY = "PACKAGE_NAME"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index c2f1f61..2e68cec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -107,6 +108,7 @@
rivSubComponentFactory,
metricsLogger,
logBufferLogger,
+ mock<NotificationChildrenContainerLogger>(),
listContainer,
smartReplyConstants,
smartReplyController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 4c83194..608778e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -733,6 +733,36 @@
verify(lowPriVectorDrawable, times(1)).start();
}
+ @Test
+ public void isExpanded_hideSensitive_sensitiveNotExpanded()
+ throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setUserExpanded(true);
+ row.setOnKeyguard(false);
+ row.setSensitive(/* sensitive= */true, /* hideSensitive= */false);
+ row.setHideSensitive(/* hideSensitive= */true, /* animated= */false,
+ /* delay= */0L, /* duration= */0L);
+
+ // THEN
+ assertThat(row.isExpanded()).isFalse();
+ }
+
+ @Test
+ public void isExpanded_hideSensitive_nonSensitiveExpanded()
+ throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setUserExpanded(true);
+ row.setOnKeyguard(false);
+ row.setSensitive(/* sensitive= */true, /* hideSensitive= */false);
+ row.setHideSensitive(/* hideSensitive= */false, /* animated= */false,
+ /* delay= */0L, /* duration= */0L);
+
+ // THEN
+ assertThat(row.isExpanded()).isTrue();
+ }
+
private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
Drawable rightIconDrawable) {
ImageView iconView = mock(ImageView.class);
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 813bae8..df47071 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
@@ -76,7 +76,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
-import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
@@ -581,6 +581,7 @@
mock(NotificationGutsManager.class),
mDismissibilityProvider,
mock(MetricsLogger.class),
+ mock(NotificationChildrenContainerLogger.class),
mock(SmartReplyConstants.class),
mock(SmartReplyController.class),
mFeatureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index 944eb2d..a87dd2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -22,21 +22,23 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.LockscreenShadeTransitionController
-import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.util.mockito.any
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mockito.isNull
import org.mockito.Mockito.verify
@@ -46,15 +48,27 @@
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- private val centralSurfaces: CentralSurfaces = mock()
- private val systemClock = FakeSystemClock()
+
+ private val screenOffAnimationController =
+ mock<ScreenOffAnimationController>().also {
+ whenever(it.allowWakeUpIfDozing()).thenReturn(true)
+ }
+ private val statusBarStateController: StatusBarStateController = mock()
+ private val powerRepository = FakePowerRepository()
+ private val powerInteractor =
+ PowerInteractor(
+ powerRepository,
+ FalsingCollectorFake(),
+ screenOffAnimationController,
+ statusBarStateController,
+ )
+
private val keyguardTransitionController: LockscreenShadeTransitionController = mock()
private val underTest =
NotificationShelfInteractor(
keyguardRepository,
deviceEntryFaceAuthRepository,
- centralSurfaces,
- systemClock,
+ powerInteractor,
keyguardTransitionController,
)
@@ -107,10 +121,12 @@
@Test
fun goToLockedShadeFromShelf_wakesUpFromDoze() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+
underTest.goToLockedShadeFromShelf()
- verify(centralSurfaces)
- .wakeUpIfDozing(anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ assertThat(powerRepository.lastWakeReason).isNotNull()
+ assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index e9a8f3f..7ae1502 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -24,23 +24,26 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
-import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.util.mockito.any
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
@@ -54,14 +57,23 @@
@Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
// mocks
- @Mock private lateinit var centralSurfaces: CentralSurfaces
@Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
+ @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
// fakes
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- private val systemClock = FakeSystemClock()
private val a11yRepo = FakeAccessibilityRepository()
+ private val powerRepository = FakePowerRepository()
+ private val powerInteractor by lazy {
+ PowerInteractor(
+ powerRepository,
+ FalsingCollectorFake(),
+ screenOffAnimationController,
+ statusBarStateController,
+ )
+ }
// real impls
private val a11yInteractor = AccessibilityInteractor(a11yRepo)
@@ -70,13 +82,17 @@
NotificationShelfInteractor(
keyguardRepository,
deviceEntryFaceAuthRepository,
- centralSurfaces,
- systemClock,
+ powerInteractor,
keyguardTransitionController,
)
}
private val underTest by lazy { NotificationShelfViewModel(interactor, activatableViewModel) }
+ @Before
+ fun setUp() {
+ whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
+ }
+
@Test
fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest {
val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
@@ -126,10 +142,12 @@
@Test
fun onClicked_goesToLockedShade() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+
underTest.onShelfClicked()
- verify(centralSurfaces)
- .wakeUpIfDozing(ArgumentMatchers.anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ assertThat(powerRepository.lastWakeReason).isNotNull()
+ assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 8c27a7dd..8d751e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -1,10 +1,12 @@
package com.android.systemui.statusbar.notification.stack
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.flags.FeatureFlags
@@ -13,7 +15,6 @@
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
import com.android.systemui.util.mockito.mock
import junit.framework.Assert.assertEquals
@@ -35,33 +36,32 @@
@RunWithLooper
class NotificationShelfTest : SysuiTestCase() {
- @Mock private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator
- @Mock private lateinit var flags: FeatureFlags
+ @Mock
+ private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator
+ @Mock
+ private lateinit var flags: FeatureFlags
+ @Mock
+ private lateinit var ambientState: AmbientState
+ @Mock
+ private lateinit var hostLayoutController: NotificationStackScrollLayoutController
- private val shelf = NotificationShelf(
- context,
- /* attrs */ null,
- /* showNotificationShelf */true
- )
- private val shelfState = shelf.viewState as NotificationShelf.ShelfState
- private val ambientState = mock(AmbientState::class.java)
- private val hostLayoutController: NotificationStackScrollLayoutController = mock()
- private val notificationTestHelper by lazy {
- allowTestableLooperAsMainThread()
- NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this))
- }
+ private lateinit var shelf: NotificationShelf
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ val root = FrameLayout(context)
+ shelf = LayoutInflater.from(root.context)
+ .inflate(/* resource = */ R.layout.status_bar_notification_shelf,
+ /* root = */root,
+ /* attachToRoot = */false) as NotificationShelf
+
whenever(ambientState.largeScreenShadeInterpolator).thenReturn(largeScreenShadeInterpolator)
whenever(ambientState.featureFlags).thenReturn(flags)
+ whenever(ambientState.isSmallScreen).thenReturn(true)
+
shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController)
shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
- whenever(ambientState.isSmallScreen).thenReturn(true)
}
@Test
@@ -342,6 +342,127 @@
)
}
+ @Test
+ fun updateState_withNullLastVisibleBackgroundChild_hideShelf() {
+ // GIVEN
+ shelf.setSensitiveRevealAnimEnabled(true)
+ whenever(ambientState.stackY).thenReturn(100f)
+ whenever(ambientState.stackHeight).thenReturn(100f)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ val endOfStack = 200f + paddingBetweenElements
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ stackScrollAlgorithmState.firstViewInShelf = mock()
+
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(null)
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(endOfStack, shelfState.yTranslation)
+ }
+
+ @Test
+ fun updateState_withNullFirstViewInShelf_hideShelf() {
+ // GIVEN
+ shelf.setSensitiveRevealAnimEnabled(true)
+ whenever(ambientState.stackY).thenReturn(100f)
+ whenever(ambientState.stackHeight).thenReturn(100f)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ val endOfStack = 200f + paddingBetweenElements
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+
+ stackScrollAlgorithmState.firstViewInShelf = null
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(endOfStack, shelfState.yTranslation)
+ }
+
+ @Test
+ fun updateState_withCollapsedShade_hideShelf() {
+ // GIVEN
+ shelf.setSensitiveRevealAnimEnabled(true)
+ whenever(ambientState.stackY).thenReturn(100f)
+ whenever(ambientState.stackHeight).thenReturn(100f)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ val endOfStack = 200f + paddingBetweenElements
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ stackScrollAlgorithmState.firstViewInShelf = mock()
+
+ whenever(ambientState.isShadeExpanded).thenReturn(false)
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(endOfStack, shelfState.yTranslation)
+ }
+
+ @Test
+ fun updateState_withHiddenSectionBeforeShelf_hideShelf() {
+ // GIVEN
+ shelf.setSensitiveRevealAnimEnabled(true)
+ whenever(ambientState.stackY).thenReturn(100f)
+ whenever(ambientState.stackHeight).thenReturn(100f)
+ val paddingBetweenElements =
+ context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
+ val endOfStack = 200f + paddingBetweenElements
+ whenever(ambientState.isShadeExpanded).thenReturn(true)
+ val lastVisibleBackgroundChild = mock<ExpandableView>()
+ val expandableViewState = ExpandableViewState()
+ whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
+ val stackScrollAlgorithmState = StackScrollAlgorithmState()
+ whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
+
+ val ssaVisibleChild = mock<ExpandableView>()
+ val ssaVisibleChildState = ExpandableViewState()
+ ssaVisibleChildState.hidden = true
+ whenever(ssaVisibleChild.viewState).thenReturn(ssaVisibleChildState)
+
+ val ssaVisibleChild1 = mock<ExpandableView>()
+ val ssaVisibleChildState1 = ExpandableViewState()
+ ssaVisibleChildState1.hidden = true
+ whenever(ssaVisibleChild1.viewState).thenReturn(ssaVisibleChildState1)
+
+ stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild)
+ stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild1)
+ whenever(ambientState.isExpansionChanging).thenReturn(true)
+ stackScrollAlgorithmState.firstViewInShelf = ssaVisibleChild1
+
+ // WHEN
+ shelf.updateState(stackScrollAlgorithmState, ambientState)
+
+ // THEN
+ val shelfState = shelf.viewState as NotificationShelf.ShelfState
+ assertEquals(true, shelfState.hidden)
+ assertEquals(endOfStack, shelfState.yTranslation)
+ }
+
private fun setFractionToShade(fraction: Float) {
whenever(ambientState.fractionToShade).thenReturn(fraction)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 18cf876..bb9937b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -79,7 +79,6 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -132,7 +131,6 @@
@Mock(answer = Answers.RETURNS_SELF)
private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
- @Mock private CentralSurfaces mCentralSurfaces;
@Mock private ScrimController mScrimController;
@Mock private GroupExpansionManager mGroupExpansionManager;
@Mock private SectionHeaderController mSilentHeaderController;
@@ -619,7 +617,6 @@
new FalsingManagerFake(),
mResources,
mNotificationSwipeHelperBuilder,
- mCentralSurfaces,
mScrimController,
mGroupExpansionManager,
mSilentHeaderController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index ee02a7b..8ad271b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -61,7 +61,6 @@
import android.view.WindowInsetsAnimation;
import android.widget.TextView;
-import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.keyguard.BouncerPanelExpansionCalculator;
@@ -84,12 +83,11 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -103,7 +101,6 @@
/**
* Tests for {@link NotificationStackScrollLayout}.
*/
-@Ignore("b/255552856")
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -113,7 +110,6 @@
private NotificationStackScrollLayout mStackScrollerInternal; // See explanation below
private AmbientState mAmbientState;
private TestableResources mTestableResources;
-
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Mock private NotificationsController mNotificationsController;
@Mock private SysuiStatusBarStateController mBarState;
@@ -128,7 +124,7 @@
@Mock private NotificationSection mNotificationSection;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
- @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -136,7 +132,6 @@
@Mock private FeatureFlags mFeatureFlags;
@Before
- @UiThreadTest
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
mTestableResources = mContext.getOrCreateTestableResources();
@@ -162,7 +157,7 @@
mDependency.injectTestDependency(AmbientState.class, mAmbientState);
mDependency.injectTestDependency(NotificationShelf.class, mNotificationShelf);
mDependency.injectTestDependency(
- UnlockedScreenOffAnimationController.class, mUnlockedScreenOffAnimationController);
+ ScreenOffAnimationController.class, mScreenOffAnimationController);
NotificationShelfController notificationShelfController =
mock(NotificationShelfController.class);
@@ -364,7 +359,6 @@
}
@Test
- @UiThreadTest
public void testSetExpandedHeight_listenerReceivedCallbacks() {
final float expectedHeight = 0f;
@@ -375,20 +369,6 @@
}
@Test
- public void testAppearFractionCalculation() {
- // appear start position
- when(mNotificationShelf.getIntrinsicHeight()).thenReturn(100);
- // because it's the same as shelf height, appear start position equals shelf height
- mStackScroller.mStatusBarHeight = 100;
- // appear end position
- when(mEmptyShadeView.getHeight()).thenReturn(200);
-
- assertEquals(0f, mStackScroller.calculateAppearFraction(100));
- assertEquals(1f, mStackScroller.calculateAppearFraction(200));
- assertEquals(0.5f, mStackScroller.calculateAppearFraction(150));
- }
-
- @Test
public void testAppearFractionCalculationIsNotNegativeWhenShelfBecomesSmaller() {
// this situation might occur if status bar height is defined in pixels while shelf height
// in dp and screen density changes - appear start position
@@ -405,7 +385,6 @@
}
@Test
- @UiThreadTest
public void testSetExpandedHeight_withSplitShade_doesntInterpolateStackHeight() {
mTestableResources
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
@@ -590,6 +569,7 @@
@Test
public void testReInflatesFooterViews() {
+ when(mEmptyShadeView.getTextResource()).thenReturn(R.string.empty_shade_text);
clearInvocations(mStackScroller);
mStackScroller.reinflateViews();
verify(mStackScroller).setFooterView(any());
@@ -597,21 +577,18 @@
}
@Test
- @UiThreadTest
public void testSetIsBeingDraggedResetsExposedMenu() {
mStackScroller.setIsBeingDragged(true);
verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
- @UiThreadTest
public void testPanelTrackingStartResetsExposedMenu() {
mStackScroller.onPanelTrackingStarted();
verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
- @UiThreadTest
public void testDarkModeResetsExposedMenu() {
mStackScroller.setHideAmount(0.1f, 0.1f);
verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
@@ -916,7 +893,7 @@
mStackScroller.setHasFilteredOutSeenNotifications(true);
mStackScroller.updateEmptyShadeView(true, false);
- verify(mEmptyShadeView).setFooterText(not(0));
+ verify(mEmptyShadeView).setFooterText(not(eq(0)));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index d107a0e..4c97d20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -815,6 +815,74 @@
)
}
+ // region shouldPinHunToBottomOfExpandedQs
+ @Test
+ fun shouldHunBeVisibleWhenScrolled_mustStayOnScreenFalse_false() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */false,
+ /* headsUpIsVisible= */false,
+ /* showingPulsing= */false,
+ /* isOnKeyguard=*/false,
+ /*headsUpOnKeyguard=*/false
+ )).isFalse()
+ }
+
+ @Test
+ fun shouldPinHunToBottomOfExpandedQs_headsUpIsVisible_false() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */true,
+ /* headsUpIsVisible= */true,
+ /* showingPulsing= */false,
+ /* isOnKeyguard=*/false,
+ /*headsUpOnKeyguard=*/false
+ )).isFalse()
+ }
+
+ @Test
+ fun shouldHunBeVisibleWhenScrolled_showingPulsing_false() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */true,
+ /* headsUpIsVisible= */false,
+ /* showingPulsing= */true,
+ /* isOnKeyguard=*/false,
+ /* headsUpOnKeyguard= */false
+ )).isFalse()
+ }
+
+ @Test
+ fun shouldHunBeVisibleWhenScrolled_isOnKeyguard_false() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */true,
+ /* headsUpIsVisible= */false,
+ /* showingPulsing= */false,
+ /* isOnKeyguard=*/true,
+ /* headsUpOnKeyguard= */false
+ )).isFalse()
+ }
+
+ @Test
+ fun shouldHunBeVisibleWhenScrolled_isNotOnKeyguard_true() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */true,
+ /* headsUpIsVisible= */false,
+ /* showingPulsing= */false,
+ /* isOnKeyguard=*/false,
+ /* headsUpOnKeyguard= */false
+ )).isTrue()
+ }
+
+ @Test
+ fun shouldHunBeVisibleWhenScrolled_headsUpOnKeyguard_true() {
+ assertThat(stackScrollAlgorithm.shouldHunBeVisibleWhenScrolled(
+ /* mustStayOnScreen= */true,
+ /* headsUpIsVisible= */false,
+ /* showingPulsing= */false,
+ /* isOnKeyguard=*/true,
+ /* headsUpOnKeyguard= */true
+ )).isTrue()
+ }
+ // endregion
+
private fun createHunViewMock(
isShadeOpen: Boolean,
fullyVisible: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index cb71fb8..036b8be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -150,7 +150,6 @@
mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
- verify(mCentralSurfaces).updateQsExpansionEnabled();
verify(mShadeController).animateCollapseShade();
}
@@ -162,7 +161,6 @@
when(mCommandQueue.panelsEnabled()).thenReturn(true);
mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
StatusBarManager.DISABLE2_NONE, false);
- verify(mCentralSurfaces).updateQsExpansionEnabled();
verify(mShadeController, never()).animateCollapseShade();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 21dae03..1ffffe4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -29,7 +29,6 @@
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;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -98,7 +97,9 @@
import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.back.domain.interactor.BackActionInteractor;
import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.charging.WiredChargingRippleController;
import com.android.systemui.classifier.FalsingCollectorFake;
@@ -113,7 +114,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
@@ -122,6 +122,7 @@
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.settings.brightness.BrightnessSliderController;
@@ -260,6 +261,7 @@
@Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
@Mock private SysuiColorExtractor mColorExtractor;
private WakefulnessLifecycle mWakefulnessLifecycle;
+ @Mock private PowerInteractor mPowerInteractor;
@Mock private ColorExtractor.GradientColors mGradientColors;
@Mock private PulseExpansionHandler mPulseExpansionHandler;
@Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
@@ -279,6 +281,7 @@
@Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
@Mock private LockscreenWallpaper mLockscreenWallpaper;
@Mock private DozeServiceHost mDozeServiceHost;
+ @Mock private BackActionInteractor mBackActionInteractor;
@Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
@Mock private VolumeComponent mVolumeComponent;
@Mock private CommandQueue mCommandQueue;
@@ -351,6 +354,9 @@
// For the Shade to animate during the Back gesture, we must enable the animation flag.
mFeatureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true);
mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
+ // Turn AOD on and toggle feature flag for jank fixes
+ mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
@@ -492,6 +498,7 @@
mColorExtractor,
mScreenLifecycle,
mWakefulnessLifecycle,
+ mPowerInteractor,
mStatusBarStateController,
Optional.of(mBubbles),
() -> mNoteTaskController,
@@ -502,13 +509,16 @@
configurationController,
mNotificationShadeWindowController,
mNotificationShelfController,
+ mStackScrollerController,
mDozeParameters,
mScrimController,
mLockscreenWallpaperLazy,
mBiometricUnlockControllerLazy,
mAuthRippleController,
mDozeServiceHost,
- mPowerManager, mScreenPinningRequest,
+ mBackActionInteractor,
+ mPowerManager,
+ mScreenPinningRequest,
mDozeScrimController,
mVolumeComponent,
mCommandQueue,
@@ -583,8 +593,6 @@
mCentralSurfaces.mPresenter = mNotificationPresenter;
mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;
mCentralSurfaces.mBarService = mBarService;
- mCentralSurfaces.mStackScrollerController = mStackScrollerController;
- mCentralSurfaces.mStackScroller = mStackScroller;
mCentralSurfaces.mGestureWakeLock = mPowerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "sysui:GestureWakeLock");
mCentralSurfaces.startKeyguard();
@@ -822,9 +830,9 @@
eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
mOnBackInvokedCallback.capture());
- when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
+ when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
mOnBackInvokedCallback.getValue().onBackInvoked();
- verify(mShadeController).animateCollapseShade();
+ verify(mBackActionInteractor).onBackRequested();
}
/**
@@ -842,6 +850,7 @@
OnBackAnimationCallback onBackAnimationCallback =
(OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
+ when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 100.0f, 1.0f, BackEvent.EDGE_LEFT);
@@ -864,6 +873,7 @@
OnBackAnimationCallback onBackAnimationCallback =
(OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
+ when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 10.0f, 0.0f, BackEvent.EDGE_LEFT);
@@ -1241,34 +1251,6 @@
}
@Test
- public void dozing_wakeUp() throws RemoteException {
- // GIVEN can wakeup when dozing & is dozing
- when(mScreenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true);
- setDozing(true);
-
- // WHEN wakeup is requested
- final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
-
- // THEN power manager receives wakeup
- verify(mPowerManagerService).wakeUp(eq(0L), eq(wakeReason), anyString(), anyString());
- }
-
- @Test
- public void notDozing_noWakeUp() throws RemoteException {
- // GIVEN can wakeup when dozing and NOT dozing
- when(mScreenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true);
- setDozing(false);
-
- // WHEN wakeup is requested
- final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
-
- // THEN power manager receives wakeup
- verify(mPowerManagerService, never()).wakeUp(anyLong(), anyInt(), anyString(), anyString());
- }
-
- @Test
public void frpLockedDevice_shadeDisabled() {
when(mDeviceProvisionedController.isFrpActive()).thenReturn(true);
when(mDozeServiceHost.isPulsing()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
index 6068f0d..5cea931 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone;
+import static android.view.View.ACCESSIBILITY_LIVE_REGION_NONE;
+import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
+
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
@@ -57,6 +60,22 @@
}
@Test
+ public void alwaysAnnounce_setsLiveRegionToNone() {
+ mKeyguardIndicationTextView.setAlwaysAnnounceEnabled(true);
+
+ assertThat(mKeyguardIndicationTextView.getAccessibilityLiveRegion()).isEqualTo(
+ ACCESSIBILITY_LIVE_REGION_NONE);
+ }
+
+ @Test
+ public void alwaysAnnounce_setsLiveRegionToDefaultPolite_whenDisabled() {
+ mKeyguardIndicationTextView.setAlwaysAnnounceEnabled(false);
+
+ assertThat(mKeyguardIndicationTextView.getAccessibilityLiveRegion()).isEqualTo(
+ ACCESSIBILITY_LIVE_REGION_POLITE);
+ }
+
+ @Test
public void switchIndication_emptyText_hideIndication() {
mKeyguardIndicationTextView.switchIndication("" /* text */, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 914e295..548e1b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -60,16 +60,16 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.bouncer.ui.BouncerView;
-import com.android.systemui.bouncer.ui.BouncerViewDelegate;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.ui.BouncerView;
+import com.android.systemui.bouncer.ui.BouncerViewDelegate;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
import com.android.systemui.plugins.ActivityStarter;
@@ -647,21 +647,21 @@
@Test
public void testReportBouncerOnDreamWhenVisible() {
mBouncerExpansionCallback.onVisibilityChanged(true);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ assertFalse(mStatusBarKeyguardViewManager.isBouncerShowingOverDream());
Mockito.clearInvocations(mCentralSurfaces);
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
mBouncerExpansionCallback.onVisibilityChanged(true);
- verify(mCentralSurfaces).setBouncerShowingOverDream(true);
+ assertTrue(mStatusBarKeyguardViewManager.isBouncerShowingOverDream());
}
@Test
public void testReportBouncerOnDreamWhenNotVisible() {
mBouncerExpansionCallback.onVisibilityChanged(false);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ assertFalse(mStatusBarKeyguardViewManager.isBouncerShowingOverDream());
Mockito.clearInvocations(mCentralSurfaces);
when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
mBouncerExpansionCallback.onVisibilityChanged(false);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
+ assertFalse(mStatusBarKeyguardViewManager.isBouncerShowingOverDream());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 1724f27..5bd6ff4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -37,6 +37,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.QuickSettingsController;
@@ -55,6 +56,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -80,6 +82,8 @@
private FakeMetricsLogger mMetricsLogger;
private final ShadeController mShadeController = mock(ShadeController.class);
private final CentralSurfaces mCentralSurfaces = mock(CentralSurfaces.class);
+ private final NotificationsInteractor mNotificationsInteractor =
+ mock(NotificationsInteractor.class);
private final KeyguardStateController mKeyguardStateController =
mock(KeyguardStateController.class);
private final NotifPipelineFlags mNotifPipelineFlags = mock(NotifPipelineFlags.class);
@@ -122,7 +126,9 @@
mock(DynamicPrivacyController.class),
mKeyguardStateController,
mCentralSurfaces,
+ mNotificationsInteractor,
mock(LockscreenShadeTransitionController.class),
+ mock(PowerInteractor.class),
mCommandQueue,
mock(NotificationLockscreenUserManager.class),
mock(SysuiStatusBarStateController.class),
@@ -233,9 +239,9 @@
.setTag("a")
.setNotification(n)
.build();
- when(mCentralSurfaces.areNotificationAlertsDisabled()).thenReturn(true);
+ when(mNotificationsInteractor.areNotificationAlertsEnabled()).thenReturn(false);
- assertTrue("CentralSurfaces alerts disabled shouldn't allow interruptions",
+ assertTrue("When alerts aren't enabled, interruptions are suppressed",
mInterruptSuppressor.suppressInterruptions(entry));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index 9bc49ae..87d813c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -50,7 +50,6 @@
val actualString = stringWriter.toString()
val expectedLogString =
disableFlagsLogger.getDisableFlagsString(
- old = null,
new = state,
newAfterLocalModification = null,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index 67727ae..d1c38f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -77,6 +77,7 @@
)
whenever(controller.users).thenAnswer { users }
+ whenever(controller.isUserSwitcherEnabled).thenReturn(true)
underTest =
object : BaseUserSwitcherAdapter(controller) {
@@ -162,6 +163,19 @@
}
@Test
+ fun count_onlyShowsCurrentUserWhenMultiUserDisabled() {
+ whenever(controller.isUserSwitcherEnabled).thenReturn(false)
+ assertThat(underTest.count).isEqualTo(1)
+ assertThat(underTest.getItem(0).isCurrent).isTrue()
+ }
+
+ @Test
+ fun count_doesNotIgnoreAllOtherUsersWhenMultiUserEnabled() {
+ whenever(controller.isUserSwitcherEnabled).thenReturn(true)
+ assertThat(underTest.count).isEqualTo(users.size)
+ }
+
+ @Test
fun getItem() {
assertThat((0 until underTest.count).map { position -> underTest.getItem(position) })
.isEqualTo(users)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index 8290dab..1ab62d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.tiles.UserDetailItemView
import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.util.mockito.whenever
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
@@ -68,6 +69,8 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(userSwitcherController.isUserSwitcherEnabled).thenReturn(true)
+
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, layoutInflater)
`when`(layoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
.thenReturn(inflatedUserDetailItemView)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index ef3a332..8f725be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -16,19 +16,13 @@
package com.android.systemui.volume;
-import static android.media.AudioManager.RINGER_MODE_NORMAL;
-import static android.media.AudioManager.RINGER_MODE_SILENT;
-import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-
import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
-import static org.junit.Assume.assumeNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -299,7 +293,7 @@
@Test
public void testSelectVibrateFromDrawer() {
final State initialUnsetState = new State();
- initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
+ initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
mDialog.onStateChangedH(initialUnsetState);
mActiveRinger.performClick();
@@ -313,7 +307,7 @@
@Test
public void testSelectMuteFromDrawer() {
final State initialUnsetState = new State();
- initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
+ initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
mDialog.onStateChangedH(initialUnsetState);
mActiveRinger.performClick();
@@ -335,7 +329,7 @@
// Make sure we've actually changed the ringer mode.
verify(mVolumeDialogController, times(1)).setRingerMode(
- RINGER_MODE_NORMAL, false);
+ AudioManager.RINGER_MODE_NORMAL, false);
}
/**
@@ -517,87 +511,6 @@
}
}
- private enum RingerDrawerState {INIT, OPEN, CLOSE}
-
- @Test
- public void ringerModeNormal_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.INIT);
- }
-
- @Test
- public void ringerModeSilent_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.INIT);
- }
-
- @Test
- public void ringerModeVibrate_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.INIT);
- }
-
- @Test
- public void ringerModeNormal_openDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.OPEN);
- }
-
- @Test
- public void ringerModeSilent_openDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.OPEN);
- }
-
- @Test
- public void ringerModeVibrate_openDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.OPEN);
- }
-
- @Test
- public void ringerModeNormal_closeDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.CLOSE);
- }
-
- @Test
- public void ringerModeSilent_closeDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.CLOSE);
- }
-
- @Test
- public void ringerModeVibrate_closeDrawer_ringerContainerDescribesItsState() {
- assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.CLOSE);
- }
-
- /**
- * The content description should include ringer state, and the correct one.
- */
- private void assertRingerContainerDescribesItsState(int ringerMode,
- RingerDrawerState drawerState) {
- State state = createShellState();
- state.ringerModeInternal = ringerMode;
- mDialog.onStateChangedH(state);
-
- mDialog.show(SHOW_REASON_UNKNOWN);
-
- if (drawerState != RingerDrawerState.INIT) {
- // in both cases we first open the drawer
- mDialog.toggleRingerDrawer(true);
-
- if (drawerState == RingerDrawerState.CLOSE) {
- mDialog.toggleRingerDrawer(false);
- }
- }
-
- String ringerContainerDescription = mDialog.getSelectedRingerContainerDescription();
- assumeNotNull(ringerContainerDescription);
-
- String ringerDescription = mContext.getString(
- mDialog.getStringDescriptionResourceForRingerMode(ringerMode));
-
- if (drawerState == RingerDrawerState.OPEN) {
- assertEquals(ringerDescription, ringerContainerDescription);
- } else {
- assertNotSame(ringerDescription, ringerContainerDescription);
- assertTrue(ringerContainerDescription.startsWith(ringerDescription));
- }
- }
-
@After
public void teardown() {
if (mDialog != null) {
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 2158396..06e6162 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -133,15 +133,19 @@
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.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
+import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.StackEducationViewKt;
+import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -151,7 +155,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -300,6 +303,8 @@
private UserHandle mUser0;
+ private FakeBubbleProperties mBubbleProperties;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -361,6 +366,7 @@
mock(UserTracker.class)
);
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
+ mBubbleProperties = new FakeBubbleProperties();
mBubbleController = new TestableBubbleController(
mContext,
mShellInit,
@@ -385,7 +391,8 @@
mock(Handler.class),
mTaskViewTransitions,
mock(SyncTransactionQueue.class),
- mock(IWindowManager.class));
+ mock(IWindowManager.class),
+ mBubbleProperties);
mBubbleController.setExpandListener(mBubbleExpandListener);
spyOn(mBubbleController);
@@ -476,7 +483,7 @@
public void testAddBubble() {
mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -484,7 +491,7 @@
assertFalse(mBubbleController.hasBubbles());
mBubbleController.updateBubble(mBubbleEntry);
assertTrue(mBubbleController.hasBubbles());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -499,7 +506,7 @@
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -562,7 +569,7 @@
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -581,7 +588,7 @@
mBubbleData.setExpanded(true);
assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Make sure the notif is suppressed
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
@@ -590,11 +597,10 @@
mBubbleController.collapseStack();
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
assertStackCollapsed();
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
- @Ignore("Currently broken.")
public void testCollapseAfterChangingExpandedBubble() {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow);
@@ -613,7 +619,7 @@
assertStackExpanded();
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
true, mRow2.getKey());
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Last added is the one that is expanded
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
@@ -638,7 +644,7 @@
// Collapse
mBubbleController.collapseStack();
assertStackCollapsed();
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -658,7 +664,7 @@
mBubbleData.setExpanded(true);
assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Notif is suppressed after expansion
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
@@ -683,7 +689,7 @@
mBubbleData.setExpanded(true);
assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Notif is suppressed after expansion
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
@@ -712,7 +718,7 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
@@ -743,7 +749,7 @@
// We should be collapsed
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
assertFalse(mBubbleController.hasBubbles());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -756,7 +762,7 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
assertStackExpanded();
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
@@ -771,7 +777,7 @@
// We should be collapsed
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
assertFalse(mBubbleController.hasBubbles());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@@ -789,7 +795,7 @@
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
mRow.getKey());
assertStackCollapsed();
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -805,7 +811,7 @@
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
mRow.getKey());
assertStackExpanded();
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -822,7 +828,7 @@
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -844,7 +850,7 @@
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -1249,11 +1255,11 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertStackExpanded();
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Show the menu
stackView.showManageMenu(true);
- assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
assertTrue(stackView.isManageMenuSettingsVisible());
assertTrue(stackView.isManageMenuDontBubbleVisible());
}
@@ -1267,11 +1273,11 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertStackExpanded();
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Show the menu
stackView.showManageMenu(true);
- assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
assertFalse(stackView.isManageMenuSettingsVisible());
assertFalse(stackView.isManageMenuDontBubbleVisible());
}
@@ -1285,15 +1291,15 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertStackExpanded();
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Show the menu
stackView.showManageMenu(true);
- assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
// Hide the menu
stackView.showManageMenu(false);
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -1305,16 +1311,16 @@
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertStackExpanded();
- assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
// Show the menu
stackView.showManageMenu(true);
- assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
+ assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
// Collapse the stack
mBubbleData.setExpanded(false);
- assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
+ assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
}
@Test
@@ -1576,7 +1582,7 @@
NotificationListenerService.RankingMap rankingMap =
mock(NotificationListenerService.RankingMap.class);
- when(rankingMap.getOrderedKeys()).thenReturn(new String[] { mBubbleEntry.getKey() });
+ when(rankingMap.getOrderedKeys()).thenReturn(new String[]{mBubbleEntry.getKey()});
mBubbleController.onRankingUpdated(rankingMap, entryDataByKey);
// Should no longer be in the stack
@@ -1884,7 +1890,111 @@
);
}
- /** Creates a bubble using the userId and package. */
+ @Test
+ public void registerBubbleBarListener_barDisabled_largeScreen_shouldBeIgnored() {
+ mBubbleProperties.mIsBubbleBarEnabled = false;
+ mPositioner.setIsLargeScreen(true);
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertTrue(mBubbleController.hasBubbles());
+
+ assertStackMode();
+
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ assertStackMode();
+
+ assertThat(mBubbleController.getStackView().getBubbleCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void registerBubbleBarListener_barEnabled_smallScreen_shouldBeIgnored() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(false);
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertTrue(mBubbleController.hasBubbles());
+
+ assertStackMode();
+
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ assertStackMode();
+
+ assertThat(mBubbleController.getStackView().getBubbleCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void registerBubbleBarListener_switchToBarAndBackToStack() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertTrue(mBubbleController.hasBubbles());
+
+ assertStackMode();
+
+ assertThat(mBubbleData.getBubbles()).hasSize(1);
+ assertBubbleIsInflatedForStack(mBubbleData.getBubbles().get(0));
+ assertBubbleIsInflatedForStack(mBubbleData.getOverflow());
+
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ assertBarMode();
+
+ assertThat(mBubbleData.getBubbles()).hasSize(1);
+ assertBubbleIsInflatedForBar(mBubbleData.getBubbles().get(0));
+ assertBubbleIsInflatedForBar(mBubbleData.getOverflow());
+
+ mBubbleController.unregisterBubbleStateListener();
+
+ assertStackMode();
+
+ assertThat(mBubbleData.getBubbles()).hasSize(1);
+ assertBubbleIsInflatedForStack(mBubbleData.getBubbles().get(0));
+ assertBubbleIsInflatedForStack(mBubbleData.getOverflow());
+ }
+
+ @Test
+ public void switchBetweenBarAndStack_noBubbles_shouldBeIgnored() {
+ mBubbleProperties.mIsBubbleBarEnabled = false;
+ mPositioner.setIsLargeScreen(true);
+ assertFalse(mBubbleController.hasBubbles());
+
+ assertNoBubbleContainerViews();
+
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+ assertNoBubbleContainerViews();
+
+ mBubbleController.unregisterBubbleStateListener();
+
+ assertNoBubbleContainerViews();
+ }
+
+ @Test
+ public void bubbleBarBubbleExpandedAndCollapsed() {
+ mBubbleProperties.mIsBubbleBarEnabled = true;
+ mPositioner.setIsLargeScreen(true);
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+ mBubbleController.registerBubbleStateListener(bubbleStateListener);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), true);
+
+ assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
+
+ mBubbleController.collapseStack();
+
+ assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
+ }
+
+ /** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
NotificationEntry workEntry = new NotificationEntryBuilder()
@@ -2000,6 +2110,44 @@
assertFalse(mBubbleController.getImplCachedState().isStackExpanded());
}
+ /** Asserts that both the bubble stack and bar views don't exist. */
+ private void assertNoBubbleContainerViews() {
+ assertThat(mBubbleController.getStackView()).isNull();
+ assertThat(mBubbleController.getLayerView()).isNull();
+ }
+
+ /** Asserts that the stack is created and the bar is null. */
+ private void assertStackMode() {
+ assertThat(mBubbleController.getStackView()).isNotNull();
+ assertThat(mBubbleController.getLayerView()).isNull();
+ }
+
+ /** Asserts that the given bubble has the stack expanded view inflated. */
+ private void assertBubbleIsInflatedForStack(BubbleViewProvider b) {
+ assertThat(b.getIconView()).isNotNull();
+ assertThat(b.getExpandedView()).isNotNull();
+ assertThat(b.getBubbleBarExpandedView()).isNull();
+ }
+
+ /** Asserts that the bar is created and the stack is null. */
+ private void assertBarMode() {
+ assertThat(mBubbleController.getStackView()).isNull();
+ assertThat(mBubbleController.getLayerView()).isNotNull();
+ }
+
+ /** Asserts that the given bubble has the bar expanded view inflated. */
+ private void assertBubbleIsInflatedForBar(BubbleViewProvider b) {
+ // the icon view should be inflated for the overflow but not for other bubbles when showing
+ // in the bar
+ if (b instanceof Bubble) {
+ assertThat(b.getIconView()).isNull();
+ } else if (b instanceof BubbleOverflow) {
+ assertThat(b.getIconView()).isNotNull();
+ }
+ assertThat(b.getExpandedView()).isNull();
+ assertThat(b.getBubbleBarExpandedView()).isNotNull();
+ }
+
/**
* Asserts that a bubble notification is suppressed from the shade and also validates the cached
* state is updated.
@@ -2029,4 +2177,19 @@
assertThat(mSysUiStateBubblesExpanded).isEqualTo(stackExpanded);
assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded);
}
+
+ private static class FakeBubbleStateListener implements Bubbles.BubbleStateListener {
+ @Override
+ public void onBubbleStateChange(BubbleBarUpdate update) {
+ }
+ }
+
+ private static class FakeBubbleProperties implements BubbleProperties {
+ boolean mIsBubbleBarEnabled = false;
+
+ @Override
+ public boolean isBubbleBarEnabled() {
+ return mIsBubbleBarEnabled;
+ }
+ }
}
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 14c3f3c..5855347 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -31,6 +31,7 @@
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.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
@@ -74,13 +75,14 @@
Handler shellMainHandler,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue,
- IWindowManager wmService) {
+ IWindowManager wmService,
+ BubbleProperties bubbleProperties) {
super(context, shellInit, shellCommandHandler, shellController, data, Runnable::run,
floatingContentCoordinator, dataRepository, statusBarService, windowManager,
windowManagerShellWrapper, userManager, launcherApps, bubbleLogger,
taskStackListener, shellTaskOrganizer, positioner, displayController,
oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
- new SyncExecutor(), taskViewTransitions, syncQueue, wmService);
+ new SyncExecutor(), taskViewTransitions, syncQueue, wmService, bubbleProperties);
setInflateSynchronously(true);
onInit();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
index 6edc373..047dc65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
@@ -27,6 +27,7 @@
public class TestableBubblePositioner extends BubblePositioner {
private int mMaxBubbles;
+ private boolean mIsLargeScreen = false;
public TestableBubblePositioner(Context context,
WindowManager windowManager) {
@@ -46,4 +47,13 @@
public int getMaxBubbles() {
return mMaxBubbles;
}
+
+ public void setIsLargeScreen(boolean isLargeScreen) {
+ mIsLargeScreen = isLargeScreen;
+ }
+
+ @Override
+ public boolean isLargeScreen() {
+ return mIsLargeScreen;
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFaceSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFaceSettingsRepository.kt
new file mode 100644
index 0000000..af2706e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFaceSettingsRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.biometrics.data.repository
+
+import kotlinx.coroutines.flow.flowOf
+
+/** Fake settings for tests. */
+class FakeFaceSettingsRepository : FaceSettingsRepository {
+
+ private val userRepositories = mutableMapOf<Int, FaceUserSettingsRepository>()
+
+ /** Add fixed settings for a user. */
+ fun setUserSettings(userId: Int, alwaysRequireConfirmationInApps: Boolean = false) {
+ userRepositories[userId] =
+ object : FaceUserSettingsRepository {
+ override val userId = userId
+ override val alwaysRequireConfirmationInApps =
+ flowOf(alwaysRequireConfirmationInApps)
+ }
+ }
+
+ override fun forUser(id: Int?) = userRepositories[id] ?: FaceUserSettingsRepositoryImpl.Empty
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
index d270700..42ec8fed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
@@ -31,13 +31,20 @@
userId: Int,
gatekeeperChallenge: Long?,
kind: PromptKind,
- requireConfirmation: Boolean,
+ ) = setPrompt(promptInfo, userId, gatekeeperChallenge, kind, forceConfirmation = false)
+
+ fun setPrompt(
+ promptInfo: PromptInfo,
+ userId: Int,
+ gatekeeperChallenge: Long?,
+ kind: PromptKind,
+ forceConfirmation: Boolean = false,
) {
_promptInfo.value = promptInfo
_userId.value = userId
_challenge.value = gatekeeperChallenge
_kind.value = kind
- _isConfirmationRequired.value = requireConfirmation
+ _isConfirmationRequired.value = promptInfo.isConfirmationRequested || forceConfirmation
}
override fun unsetPrompt() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 1b7542b..9c4fd94 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -24,9 +24,9 @@
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
-import com.android.systemui.scene.data.model.SceneContainerConfig
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -51,7 +51,7 @@
fakeSceneContainerConfig(CONTAINER_2),
)
): SceneContainerRepository {
- return SceneContainerRepository(containerConfigurations)
+ return SceneContainerRepository(containerConfigurations.associateBy { it.name })
}
fun fakeSceneKeys(): List<SceneKey> {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index fbc2381..61e5b5f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -79,6 +79,10 @@
return _userSwitcherSettings.value.isSimpleUserSwitcher
}
+ override fun isUserSwitcherEnabled(): Boolean {
+ return _userSwitcherSettings.value.isUserSwitcherEnabled
+ }
+
fun setUserInfos(infos: List<UserInfo>) {
_userInfos.value = infos
}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 308e2cf..3406102 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -359,11 +359,7 @@
final File infoStage = new File(filesDir, WALLPAPER_INFO_STAGE);
final File imageStage = new File(filesDir, SYSTEM_WALLPAPER_STAGE);
final File lockImageStage = new File(filesDir, LOCK_WALLPAPER_STAGE);
-
- // If we restored separate lock imagery, the system wallpaper should be
- // applied as system-only; but if there's no separate lock image, make
- // sure to apply the restored system wallpaper as both.
- final int sysWhich = FLAG_SYSTEM | (lockImageStage.exists() ? 0 : FLAG_LOCK);
+ boolean lockImageStageExists = lockImageStage.exists();
try {
// First parse the live component name so that we know for logging if we care about
@@ -371,14 +367,31 @@
ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
mSystemHasLiveComponent = wpService != null;
+ ComponentName kwpService = null;
+ boolean lockscreenLiveWallpaper = mWallpaperManager.isLockscreenLiveWallpaperEnabled();
+ if (lockscreenLiveWallpaper) {
+ kwpService = parseWallpaperComponent(infoStage, "kwp");
+ }
+ mLockHasLiveComponent = kwpService != null;
+ boolean separateLockWallpaper = mLockHasLiveComponent || lockImageStage.exists();
+
+ // if there's no separate lock wallpaper, apply the system wallpaper to both screens.
+ final int sysWhich = separateLockWallpaper ? FLAG_SYSTEM : FLAG_SYSTEM | FLAG_LOCK;
+
// It is valid for the imagery to be absent; it means that we were not permitted
// to back up the original image on the source device, or there was no user-supplied
// wallpaper image present.
- restoreFromStage(imageStage, infoStage, "wp", sysWhich);
- restoreFromStage(lockImageStage, infoStage, "kwp", FLAG_LOCK);
+ if (!lockscreenLiveWallpaper) restoreFromStage(imageStage, infoStage, "wp", sysWhich);
+ if (lockImageStageExists) {
+ restoreFromStage(lockImageStage, infoStage, "kwp", FLAG_LOCK);
+ }
+ if (lockscreenLiveWallpaper) restoreFromStage(imageStage, infoStage, "wp", sysWhich);
// And reset to the wallpaper service we should be using
- updateWallpaperComponent(wpService, !lockImageStage.exists());
+ if (lockscreenLiveWallpaper && mLockHasLiveComponent) {
+ updateWallpaperComponent(kwpService, false, FLAG_LOCK);
+ }
+ updateWallpaperComponent(wpService, !lockImageStageExists, sysWhich);
} catch (Exception e) {
Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
mEventLogger.onRestoreException(e);
@@ -397,9 +410,21 @@
}
@VisibleForTesting
- void updateWallpaperComponent(ComponentName wpService, boolean applyToLock) throws IOException {
+ void updateWallpaperComponent(ComponentName wpService, boolean applyToLock, int which)
+ throws IOException {
+ boolean lockscreenLiveWallpaper = mWallpaperManager.isLockscreenLiveWallpaperEnabled();
if (servicePackageExists(wpService)) {
Slog.i(TAG, "Using wallpaper service " + wpService);
+ if (lockscreenLiveWallpaper) {
+ mWallpaperManager.setWallpaperComponentWithFlags(wpService, which);
+ if ((which & FLAG_LOCK) != 0) {
+ mEventLogger.onLockLiveWallpaperRestored(wpService);
+ }
+ if ((which & FLAG_SYSTEM) != 0) {
+ mEventLogger.onSystemLiveWallpaperRestored(wpService);
+ }
+ return;
+ }
mWallpaperManager.setWallpaperComponent(wpService);
if (applyToLock) {
// We have a live wallpaper and no static lock image,
@@ -414,7 +439,7 @@
// in reports from users
if (wpService != null) {
// TODO(b/268471749): Handle delayed case
- applyComponentAtInstall(wpService, applyToLock);
+ applyComponentAtInstall(wpService, applyToLock, which);
Slog.w(TAG, "Wallpaper service " + wpService + " isn't available. "
+ " Will try to apply later");
}
@@ -437,7 +462,8 @@
// And log the success
if ((which & FLAG_SYSTEM) > 0) {
mEventLogger.onSystemImageWallpaperRestored();
- } else {
+ }
+ if ((which & FLAG_LOCK) > 0) {
mEventLogger.onLockImageWallpaperRestored();
}
}
@@ -460,7 +486,8 @@
private void logRestoreError(int which, String error) {
if ((which & FLAG_SYSTEM) == FLAG_SYSTEM) {
mEventLogger.onSystemImageWallpaperRestoreFailed(error);
- } else if ((which & FLAG_LOCK) == FLAG_LOCK) {
+ }
+ if ((which & FLAG_LOCK) == FLAG_LOCK) {
mEventLogger.onLockImageWallpaperRestoreFailed(error);
}
}
@@ -552,16 +579,21 @@
// Intentionally blank
}
- private void applyComponentAtInstall(ComponentName componentName, boolean applyToLock) {
- PackageMonitor packageMonitor = getWallpaperPackageMonitor(componentName, applyToLock);
+ private void applyComponentAtInstall(ComponentName componentName, boolean applyToLock,
+ int which) {
+ PackageMonitor packageMonitor = getWallpaperPackageMonitor(
+ componentName, applyToLock, which);
packageMonitor.register(getBaseContext(), null, UserHandle.ALL, true);
}
@VisibleForTesting
- PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, boolean applyToLock) {
+ PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, boolean applyToLock,
+ int which) {
return new PackageMonitor() {
@Override
public void onPackageAdded(String packageName, int uid) {
+ boolean lockscreenLiveWallpaper =
+ mWallpaperManager.isLockscreenLiveWallpaperEnabled();
if (!isDeviceInRestore()) {
// We don't want to reapply the wallpaper outside a restore.
unregister();
@@ -582,16 +614,29 @@
if (componentName.getPackageName().equals(packageName)) {
Slog.d(TAG, "Applying component " + componentName);
- boolean sysResult = mWallpaperManager.setWallpaperComponent(componentName);
+ boolean success = lockscreenLiveWallpaper
+ ? mWallpaperManager.setWallpaperComponentWithFlags(componentName, which)
+ : mWallpaperManager.setWallpaperComponent(componentName);
WallpaperEventLogger logger = new WallpaperEventLogger(
mBackupManager.getDelayedRestoreLogger());
- if (sysResult) {
- logger.onSystemLiveWallpaperRestored(componentName);
+ if (success) {
+ if (!lockscreenLiveWallpaper || (which & FLAG_SYSTEM) != 0) {
+ logger.onSystemLiveWallpaperRestored(componentName);
+ }
+ if (lockscreenLiveWallpaper && (which & FLAG_LOCK) != 0) {
+ logger.onLockLiveWallpaperRestored(componentName);
+ }
} else {
- logger.onSystemLiveWallpaperRestoreFailed(
- WallpaperEventLogger.ERROR_SET_COMPONENT_EXCEPTION);
+ if (!lockscreenLiveWallpaper || (which & FLAG_SYSTEM) != 0) {
+ logger.onSystemLiveWallpaperRestoreFailed(
+ WallpaperEventLogger.ERROR_SET_COMPONENT_EXCEPTION);
+ }
+ if (lockscreenLiveWallpaper && (which & FLAG_LOCK) != 0) {
+ logger.onLockLiveWallpaperRestoreFailed(
+ WallpaperEventLogger.ERROR_SET_COMPONENT_EXCEPTION);
+ }
}
- if (applyToLock) {
+ if (applyToLock && !lockscreenLiveWallpaper) {
try {
mWallpaperManager.clear(FLAG_LOCK);
logger.onLockLiveWallpaperRestored(componentName);
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 9b07ad4..dc1126e 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -117,6 +117,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mWallpaperManager.isLockscreenLiveWallpaperEnabled()).thenReturn(true);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
@@ -364,14 +365,23 @@
mWallpaperBackupAgent.mIsDeviceInRestore = true;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
-
- verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
- verify(mWallpaperManager, times(1)).clear(eq(FLAG_LOCK));
+ if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never()).clear(anyInt());
+ } else {
+ verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
+ verify(mWallpaperManager, times(1)).clear(eq(FLAG_LOCK));
+ }
}
@Test
@@ -380,14 +390,24 @@
mWallpaperBackupAgent.mIsDeviceInRestore = true;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ false);
+ /* applyToLock */ false, FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
- verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
- verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
+ if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never()).clear(anyInt());
+ } else {
+ verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
+ verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
+ }
}
@Test
@@ -396,7 +416,7 @@
mWallpaperBackupAgent.mIsDeviceInRestore = false;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
@@ -412,7 +432,7 @@
mWallpaperBackupAgent.mIsDeviceInRestore = false;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate "wrong" wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(/* packageName */"",
@@ -614,6 +634,13 @@
mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
assertThat(result).isNotNull();
assertThat(result.getSuccessCount()).isEqualTo(1);
+
+ if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ }
}
@Test
@@ -649,19 +676,20 @@
}
@Test
- public void testOnRestore_lockWallpaperImgMissingAndNoLive_logsFailure() throws Exception {
+ public void testOnRestore_wallpaperImgMissingAndNoLive_logsFailure() throws Exception {
mockStagedWallpaperFile(WALLPAPER_INFO_STAGE);
- mockStagedWallpaperFile(SYSTEM_WALLPAPER_STAGE);
mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
BackupAnnotations.OperationType.RESTORE);
mWallpaperBackupAgent.onRestoreFinished();
- DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
- mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
- assertThat(result).isNotNull();
- assertThat(result.getFailCount()).isEqualTo(1);
- assertThat(result.getErrors()).containsKey(ERROR_NO_WALLPAPER);
+ for (String wallpaper: List.of(WALLPAPER_IMG_LOCK, WALLPAPER_IMG_SYSTEM)) {
+ DataTypeResult result = getLoggingResult(wallpaper,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_NO_WALLPAPER);
+ }
}
@Test
@@ -722,13 +750,15 @@
public void testUpdateWallpaperComponent_delayedRestore_logsSuccess() throws Exception {
mWallpaperBackupAgent.mIsDeviceInRestore = true;
when(mWallpaperManager.setWallpaperComponent(any())).thenReturn(true);
+ when(mWallpaperManager.setWallpaperComponentWithFlags(any(), eq(FLAG_LOCK | FLAG_SYSTEM)))
+ .thenReturn(true);
BackupRestoreEventLogger logger = new BackupRestoreEventLogger(
BackupAnnotations.OperationType.RESTORE);
when(mBackupManager.getDelayedRestoreLogger()).thenReturn(logger);
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -752,7 +782,7 @@
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -774,7 +804,7 @@
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true);
+ /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
@@ -909,8 +939,9 @@
@Override
PackageMonitor getWallpaperPackageMonitor(ComponentName componentName,
- boolean applyToLock) {
- mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(componentName, applyToLock);
+ boolean applyToLock, int which) {
+ mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(
+ componentName, applyToLock, which);
return mWallpaperPackageMonitor;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 63d2cda..c937447a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -451,7 +451,12 @@
if (svcConnTracingEnabled()) {
logTraceSvcConn("setOnKeyEventResult", "handled=" + handled + ";sequence=" + sequence);
}
- mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -547,24 +552,30 @@
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
- final AccessibilityWindowInfo.WindowListSparseArray allWindows =
- new AccessibilityWindowInfo.WindowListSparseArray();
- final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
- mDisplayTypes);
- final int displayListCounts = displayList.size();
- if (displayListCounts > 0) {
- for (int i = 0; i < displayListCounts; i++) {
- final int displayId = displayList.get(i);
- ensureWindowsAvailableTimedLocked(displayId);
- final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked(
- displayId);
- if (windowList != null) {
- allWindows.put(displayId, windowList);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final AccessibilityWindowInfo.WindowListSparseArray allWindows =
+ new AccessibilityWindowInfo.WindowListSparseArray();
+ final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
+ mDisplayTypes);
+ final int displayListCounts = displayList.size();
+ if (displayListCounts > 0) {
+ for (int i = 0; i < displayListCounts; i++) {
+ final int displayId = displayList.get(i);
+ ensureWindowsAvailableTimedLocked(displayId);
+
+ final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked(
+ displayId);
+ if (windowList != null) {
+ allWindows.put(displayId, windowList);
+ }
}
}
+ return allWindows;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return allWindows;
}
}
@@ -596,14 +607,19 @@
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
- AccessibilityWindowInfo window =
- mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
- if (window != null) {
- AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
- windowClone.setConnectionId(mId);
- return windowClone;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ AccessibilityWindowInfo window =
+ mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
+ if (window != null) {
+ AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
+ windowClone.setConnectionId(mId);
+ return windowClone;
+ }
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return null;
}
}
@@ -1046,7 +1062,12 @@
return false;
}
}
- return mSystemActionPerformer.performSystemAction(action);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mSystemActionPerformer.performSystemAction(action);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -1059,7 +1080,12 @@
return Collections.emptyList();
}
}
- return mSystemActionPerformer.getSystemActions();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mSystemActionPerformer.getSystemActions();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -1070,12 +1096,17 @@
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
return false;
}
- if (isCapturingFingerprintGestures()) {
- FingerprintGestureDispatcher dispatcher =
- mSystemSupport.getFingerprintGestureDispatcher();
- return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (isCapturingFingerprintGestures()) {
+ FingerprintGestureDispatcher dispatcher =
+ mSystemSupport.getFingerprintGestureDispatcher();
+ return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable();
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return false;
}
@Nullable
@@ -1285,7 +1316,12 @@
logTraceSvcConn("setMagnificationCallbackEnabled",
"displayId=" + displayId + ";enabled=" + enabled);
}
- mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
public boolean isMagnificationCallbackEnabled(int displayId) {
@@ -1297,7 +1333,12 @@
if (svcConnTracingEnabled()) {
logTraceSvcConn("setSoftKeyboardCallbackEnabled", "enabled=" + enabled);
}
- mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -1334,15 +1375,20 @@
return;
}
- RemoteAccessibilityConnection connection = mA11yWindowManager.getConnectionLocked(
- mSystemSupport.getCurrentUserIdLocked(),
- resolveAccessibilityWindowIdLocked(accessibilityWindowId));
- if (connection == null) {
- callback.sendTakeScreenshotOfWindowError(
- AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_WINDOW, interactionId);
- return;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ RemoteAccessibilityConnection connection = mA11yWindowManager.getConnectionLocked(
+ mSystemSupport.getCurrentUserIdLocked(),
+ resolveAccessibilityWindowIdLocked(accessibilityWindowId));
+ if (connection == null) {
+ callback.sendTakeScreenshotOfWindowError(
+ AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_WINDOW, interactionId);
+ return;
+ }
+ connection.getRemote().takeScreenshotOfWindow(interactionId, listener, callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- connection.getRemote().takeScreenshotOfWindow(interactionId, listener, callback);
}
@Override
@@ -1531,7 +1577,12 @@
logTraceSvcConn("getOverlayWindowToken", "displayId=" + displayId);
}
synchronized (mLock) {
- return mOverlayWindowTokens.get(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mOverlayWindowTokens.get(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1547,7 +1598,12 @@
logTraceSvcConn("getWindowIdForLeashToken", "token=" + token);
}
synchronized (mLock) {
- return mA11yWindowManager.getWindowIdLocked(token);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mA11yWindowManager.getWindowIdLocked(token);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -2394,7 +2450,12 @@
logTraceSvcConn("setGestureDetectionPassthroughRegion",
"displayId=" + displayId + ";region=" + region);
}
- mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -2403,7 +2464,12 @@
logTraceSvcConn("setTouchExplorationPassthroughRegion",
"displayId=" + displayId + ";region=" + region);
}
- mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -2432,13 +2498,20 @@
@Override
public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, Bundle callingStack) {
- if (mTrace.isA11yTracingEnabledForTypes(loggingTypes)) {
- ArrayList<StackTraceElement> list =
- (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK, java.util.ArrayList.class);
- HashSet<String> ignoreList =
- (HashSet<String>) callingStack.getSerializable(IGNORE_CALL_STACK, java.util.HashSet.class);
- mTrace.logTrace(timestamp, where, loggingTypes, callingParams, processId, threadId,
- callingUid, list.toArray(new StackTraceElement[list.size()]), ignoreList);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (mTrace.isA11yTracingEnabledForTypes(loggingTypes)) {
+ ArrayList<StackTraceElement> list =
+ (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK,
+ java.util.ArrayList.class);
+ HashSet<String> ignoreList =
+ (HashSet<String>) callingStack.getSerializable(IGNORE_CALL_STACK,
+ java.util.HashSet.class);
+ mTrace.logTrace(timestamp, where, loggingTypes, callingParams, processId, threadId,
+ callingUid, list.toArray(new StackTraceElement[list.size()]), ignoreList);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -2477,9 +2550,15 @@
mTrace.logTrace(TRACE_WM + "." + methodName, FLAGS_WINDOW_MANAGER_INTERNAL, params);
}
+ @Override
public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
- mServiceDetectsGestures.put(displayId, mode);
- mSystemSupport.setServiceDetectsGesturesEnabled(displayId, mode);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mServiceDetectsGestures.put(displayId, mode);
+ mSystemSupport.setServiceDetectsGesturesEnabled(displayId, mode);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
public boolean isServiceDetectsGesturesEnabled(int displayId) {
@@ -2489,29 +2568,60 @@
return false;
}
+ @Override
public void requestTouchExploration(int displayId) {
- mSystemSupport.requestTouchExploration(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.requestTouchExploration(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void requestDragging(int displayId, int pointerId) {
- mSystemSupport.requestDragging(displayId, pointerId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.requestDragging(displayId, pointerId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void requestDelegating(int displayId) {
- mSystemSupport.requestDelegating(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.requestDelegating(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onDoubleTap(int displayId) {
- mSystemSupport.onDoubleTap(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.onDoubleTap(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onDoubleTapAndHold(int displayId) {
- mSystemSupport.onDoubleTapAndHold(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.onDoubleTapAndHold(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Sets the scaling factor for animations.
*/
+ @Override
public void setAnimationScale(float scale) {
final long identity = Binder.clearCallingIdentity();
try {
@@ -2545,25 +2655,36 @@
@Override
public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) {
- mSystemSupport.attachAccessibilityOverlayToDisplay(displayId, sc);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSystemSupport.attachAccessibilityOverlayToDisplay(displayId, sc);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void attachAccessibilityOverlayToWindow(int accessibilityWindowId, SurfaceControl sc)
throws RemoteException {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.setTrustedOverlay(sc, true).apply();
- t.close();
- synchronized (mLock) {
- RemoteAccessibilityConnection connection =
- mA11yWindowManager.getConnectionLocked(
- mSystemSupport.getCurrentUserIdLocked(),
- resolveAccessibilityWindowIdLocked(accessibilityWindowId));
- if (connection == null) {
- Slog.e(LOG_TAG, "unable to get remote accessibility connection.");
- return;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setTrustedOverlay(sc, true).apply();
+ t.close();
+ synchronized (mLock) {
+ RemoteAccessibilityConnection connection =
+ mA11yWindowManager.getConnectionLocked(
+ mSystemSupport.getCurrentUserIdLocked(),
+ resolveAccessibilityWindowIdLocked(accessibilityWindowId));
+ if (connection == null) {
+ Slog.e(LOG_TAG, "unable to get remote accessibility connection.");
+ return;
+ }
+ connection.getRemote().attachAccessibilityOverlayToWindow(sc);
}
- connection.getRemote().attachAccessibilityOverlayToWindow(sc);
+
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 21986b7..466cda3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -74,6 +74,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
@@ -1250,7 +1251,8 @@
}
@Override
- public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
+ public ParceledListSlice<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(
+ int userId) {
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList",
FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId);
@@ -1262,8 +1264,9 @@
final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
Binder.getCallingUid());
if (mProxyManager.isProxyedDeviceId(deviceId)) {
- return mProxyManager.getInstalledAndEnabledServiceInfosLocked(
- AccessibilityServiceInfo.FEEDBACK_ALL_MASK, deviceId);
+ return new ParceledListSlice<>(
+ mProxyManager.getInstalledAndEnabledServiceInfosLocked(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK, deviceId));
}
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
@@ -1275,7 +1278,7 @@
}
if (Binder.getCallingPid() == OWN_PROCESS_ID) {
- return serviceInfos;
+ return new ParceledListSlice<>(serviceInfos);
}
final PackageManagerInternal pm = LocalServices.getService(
PackageManagerInternal.class);
@@ -1287,7 +1290,7 @@
serviceInfos.remove(i);
}
}
- return serviceInfos;
+ return new ParceledListSlice<>(serviceInfos);
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 91fe035..9e70073 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -158,10 +158,11 @@
mSystemSupport.persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
userState.getEnabledServicesLocked(), userState.mUserId);
+
+ mSystemSupport.onClientChangeLocked(false);
} finally {
Binder.restoreCallingIdentity(identity);
}
- mSystemSupport.onClientChangeLocked(false);
}
}
}
@@ -285,7 +286,13 @@
}
final AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return false;
- return userState.setSoftKeyboardModeLocked(showMode, mComponentName);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.setSoftKeyboardModeLocked(showMode, mComponentName);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -295,7 +302,12 @@
logTraceSvcConn("getSoftKeyboardShowMode", "");
}
final AccessibilityUserState userState = mUserStateWeakReference.get();
- return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -363,8 +375,14 @@
if (!hasRightsToCurrentUserLocked()) {
return false;
}
- AccessibilityUserState userState = mUserStateWeakReference.get();
- return (userState != null) && isAccessibilityButtonAvailableLocked(userState);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ AccessibilityUserState userState = mUserStateWeakReference.get();
+ return (userState != null) && isAccessibilityButtonAvailableLocked(userState);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -456,26 +474,32 @@
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
synchronized (mLock) {
if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) {
- MotionEventInjector motionEventInjector =
- mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
- if (wmTracingEnabled()) {
- logTraceWM("isTouchOrFaketouchDevice", "");
- }
- if (motionEventInjector != null
- && mWindowManagerService.isTouchOrFaketouchDevice()) {
- motionEventInjector.injectEvents(
- gestureSteps.getList(), mServiceInterface, sequence, displayId);
- } else {
- try {
- if (svcClientTracingEnabled()) {
- logTraceSvcClient("onPerformGestureResult", sequence + ", false");
- }
- mServiceInterface.onPerformGestureResult(sequence, false);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending motion event injection failure to "
- + mServiceInterface, re);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ MotionEventInjector motionEventInjector =
+ mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
+ if (wmTracingEnabled()) {
+ logTraceWM("isTouchOrFaketouchDevice", "");
}
+ if (motionEventInjector != null
+ && mWindowManagerService.isTouchOrFaketouchDevice()) {
+ motionEventInjector.injectEvents(
+ gestureSteps.getList(), mServiceInterface, sequence, displayId);
+ } else {
+ try {
+ if (svcClientTracingEnabled()) {
+ logTraceSvcClient("onPerformGestureResult", sequence + ", false");
+ }
+ mServiceInterface.onPerformGestureResult(sequence, false);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending motion event injection failure to "
+ + mServiceInterface, re);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
+
}
}
}
@@ -501,10 +525,15 @@
return;
}
- // Sets the appearance data in the A11yUserState.
- userState.setFocusAppearanceLocked(strokeWidth, color);
- // Updates the appearance data in the A11yManager.
- mSystemSupport.onClientChangeLocked(false);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // Sets the appearance data in the A11yUserState.
+ userState.setFocusAppearanceLocked(strokeWidth, color);
+ // Updates the appearance data in the A11yManager.
+ mSystemSupport.onClientChangeLocked(false);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2d60716..819f8a1 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -158,7 +158,6 @@
private static final String TAG = "AppWidgetServiceImpl";
private static final boolean DEBUG = false;
- static final boolean DEBUG_PROVIDER_INFO_CACHE = true;
private static final String OLD_KEYGUARD_HOST_PACKAGE = "android";
private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
@@ -255,7 +254,6 @@
private boolean mSafeMode;
private int mMaxWidgetBitmapMemory;
- private boolean mIsProviderInfoPersisted;
private boolean mIsCombinedBroadcastEnabled;
// Mark widget lifecycle broadcasts as 'interactive'
@@ -281,14 +279,8 @@
mCallbackHandler = new CallbackHandler(serviceThread.getLooper());
mBackupRestoreController = new BackupRestoreController();
mSecurityPolicy = new SecurityPolicy();
- mIsProviderInfoPersisted = !ActivityManager.isLowRamDeviceStatic()
- && DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.PERSISTS_WIDGET_PROVIDER_INFO, true);
mIsCombinedBroadcastEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.COMBINED_BROADCAST_ENABLED, true);
- if (DEBUG_PROVIDER_INFO_CACHE && !mIsProviderInfoPersisted) {
- Slog.d(TAG, "App widget provider info will not be persisted on this device");
- }
BroadcastOptions opts = BroadcastOptions.makeBasic();
opts.setBackgroundActivityStartsAllowed(false);
@@ -2528,21 +2520,7 @@
}
}
- private static void serializeProvider(
- @NonNull final TypedXmlSerializer out, @NonNull final Provider p) throws IOException {
- Objects.requireNonNull(out);
- Objects.requireNonNull(p);
- serializeProviderInner(out, p, false /* persistsProviderInfo */);
- }
-
- private static void serializeProviderWithProviderInfo(
- @NonNull final TypedXmlSerializer out, @NonNull final Provider p) throws IOException {
- Objects.requireNonNull(out);
- Objects.requireNonNull(p);
- serializeProviderInner(out, p, true /* persistsProviderInfo */);
- }
-
- private static void serializeProviderInner(@NonNull final TypedXmlSerializer out,
+ private static void serializeProvider(@NonNull final TypedXmlSerializer out,
@NonNull final Provider p, final boolean persistsProviderInfo) throws IOException {
Objects.requireNonNull(out);
Objects.requireNonNull(p);
@@ -2553,9 +2531,6 @@
if (!TextUtils.isEmpty(p.infoTag)) {
out.attribute(null, "info_tag", p.infoTag);
}
- if (DEBUG_PROVIDER_INFO_CACHE && persistsProviderInfo && !p.mInfoParsed) {
- Slog.d(TAG, "Provider info from " + p.id.componentName + " won't be persisted.");
- }
if (persistsProviderInfo && p.mInfoParsed) {
AppWidgetXmlUtil.writeAppWidgetProviderInfoLocked(out, p.info);
}
@@ -3172,11 +3147,7 @@
if (provider.getUserId() != userId) {
continue;
}
- if (mIsProviderInfoPersisted) {
- serializeProviderWithProviderInfo(out, provider);
- } else if (provider.shouldBePersisted()) {
- serializeProvider(out, provider);
- }
+ serializeProvider(out, provider, true /* persistsProviderInfo */);
}
N = mHosts.size();
@@ -3274,10 +3245,10 @@
provider.zombie = true;
provider.id = providerId;
mProviders.add(provider);
- } else if (mIsProviderInfoPersisted) {
+ } else {
final AppWidgetProviderInfo info =
AppWidgetXmlUtil.readAppWidgetProviderInfoLocked(parser);
- if (DEBUG_PROVIDER_INFO_CACHE && info == null) {
+ if (DEBUG && info == null) {
Slog.d(TAG, "Unable to load widget provider info from xml for "
+ providerId.componentName);
}
@@ -4601,7 +4572,7 @@
&& (provider.isInPackageForUser(backedupPackage, userId)
|| provider.hostedByPackageForUser(backedupPackage, userId))) {
provider.tag = index;
- serializeProvider(out, provider);
+ serializeProvider(out, provider, false /* persistsProviderInfo*/);
index++;
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index 7d8bb51..69b738a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -22,7 +22,6 @@
import android.content.ComponentName;
import android.os.Build;
import android.text.TextUtils;
-import android.util.Slog;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -84,8 +83,6 @@
}
if (info.label != null) {
out.attribute(null, ATTR_LABEL, info.label);
- } else if (AppWidgetServiceImpl.DEBUG_PROVIDER_INFO_CACHE) {
- Slog.e(TAG, "Label is empty in " + info.provider);
}
out.attributeInt(null, ATTR_ICON, info.icon);
out.attributeInt(null, ATTR_PREVIEW_IMAGE, info.previewImage);
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index ac77043..82af382 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -46,6 +46,7 @@
import com.android.server.utils.Slogf;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -319,6 +320,13 @@
return context.createDisplayContext(display);
}
+ static <T> @Nullable T weakDeref(WeakReference<T> weakRef, String tag, String prefix) {
+ T deref = weakRef.get();
+ if (deref == null) {
+ Slog.wtf(tag, prefix + "fail to deref " + weakRef);
+ }
+ return deref;
+ }
private interface ViewNodeFilter {
boolean matches(ViewNode node);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
index ea31074..bcca006 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
@@ -44,6 +44,8 @@
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.ServiceConnector;
+import java.lang.ref.WeakReference;
+
/**
* Class responsible for connection with the Remote {@link FieldClassificationService}.
* This class is instantiated when {@link AutofillManagerServiceImpl} is established.
@@ -133,7 +135,8 @@
}
public void onFieldClassificationRequest(@NonNull FieldClassificationRequest request,
- FieldClassificationServiceCallbacks fieldClassificationServiceCallbacks) {
+ WeakReference<FieldClassificationServiceCallbacks>
+ fieldClassificationServiceCallbacksWeakRef) {
final long startTime = SystemClock.elapsedRealtime();
if (sVerbose) {
Slog.v(TAG, "onFieldClassificationRequest request:" + request);
@@ -170,6 +173,15 @@
Slog.d(TAG, "onSuccess " + msg);
}
}
+ FieldClassificationServiceCallbacks
+ fieldClassificationServiceCallbacks =
+ Helper.weakDeref(
+ fieldClassificationServiceCallbacksWeakRef,
+ TAG, "onSuccess "
+ );
+ if (fieldClassificationServiceCallbacks == null) {
+ return;
+ }
fieldClassificationServiceCallbacks
.onClassificationRequestSuccess(response);
}
@@ -180,6 +192,15 @@
if (sDebug) {
Slog.d(TAG, "onFailure");
}
+ FieldClassificationServiceCallbacks
+ fieldClassificationServiceCallbacks =
+ Helper.weakDeref(
+ fieldClassificationServiceCallbacksWeakRef,
+ TAG, "onFailure "
+ );
+ if (fieldClassificationServiceCallbacks == null) {
+ return;
+ }
fieldClassificationServiceCallbacks
.onClassificationRequestFailure(0, null);
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 639f279..7b459aa 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -855,8 +855,12 @@
RemoteFieldClassificationService remoteFieldClassificationService =
mService.getRemoteFieldClassificationServiceLocked();
if (remoteFieldClassificationService != null) {
+ WeakReference<RemoteFieldClassificationService.FieldClassificationServiceCallbacks>
+ fieldClassificationServiceCallbacksWeakRef =
+ new WeakReference<>(Session.this);
remoteFieldClassificationService.onFieldClassificationRequest(
- mClassificationState.mPendingFieldClassificationRequest, Session.this);
+ mClassificationState.mPendingFieldClassificationRequest,
+ fieldClassificationServiceCallbacksWeakRef);
}
mClassificationState.onFieldClassificationRequestSent();
}
diff --git a/services/companion/OWNERS b/services/companion/OWNERS
index cb4cc56..734d8b6 100644
--- a/services/companion/OWNERS
+++ b/services/companion/OWNERS
@@ -1,4 +1 @@
-evanxinchen@google.com
-ewol@google.com
-guojing@google.com
-svetoslavganov@google.com
\ No newline at end of file
+include /core/java/android/companion/OWNERS
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ebcd572..89e8a18 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -67,6 +67,7 @@
import android.companion.IOnMessageReceivedListener;
import android.companion.IOnTransportsChangedListener;
import android.companion.ISystemDataTransferCallback;
+import android.companion.utils.FeatureUtils;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
@@ -761,6 +762,11 @@
@Override
public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,
int userId, int associationId) {
+ if (!FeatureUtils.isPermSyncEnabled()) {
+ throw new UnsupportedOperationException("Calling"
+ + " buildPermissionTransferUserConsentIntent, but this API is disabled by"
+ + " the system.");
+ }
return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent(
packageName, userId, associationId);
}
@@ -768,6 +774,10 @@
@Override
public void startSystemDataTransfer(String packageName, int userId, int associationId,
ISystemDataTransferCallback callback) {
+ if (!FeatureUtils.isPermSyncEnabled()) {
+ throw new UnsupportedOperationException("Calling startSystemDataTransfer, but this"
+ + " API is disabled by the system.");
+ }
mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId,
associationId, callback);
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
index fac1c89..3187de5 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
@@ -175,7 +175,8 @@
: handle.getComponentName().getShortClassName(),
phoneAccount != null ? phoneAccount.getExtras().getString(
CrossDeviceSyncController.EXTRA_CALL_FACILITATOR_ID)
- : handle.getComponentName().getPackageName());
+ : handle.getComponentName().getPackageName(),
+ handle.getComponentName().flattenToString());
call.setFacilitator(callFacilitator);
call.setDirection(android.companion.Telecom.Call.OUTGOING);
call.setCallerId(connectionRequest.getAddress().getSchemeSpecificPart());
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
index 74641a4..08811ba 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
@@ -75,13 +75,15 @@
public static class CallFacilitator {
private String mName;
private String mIdentifier;
+ private String mExtendedIdentifier;
private boolean mIsTel;
CallFacilitator() {}
- CallFacilitator(String name, String identifier) {
+ CallFacilitator(String name, String identifier, String extendedIdentifier) {
mName = name;
mIdentifier = identifier;
+ mExtendedIdentifier = extendedIdentifier;
}
public String getName() {
@@ -92,6 +94,10 @@
return mIdentifier;
}
+ public String getExtendedIdentifier() {
+ return mExtendedIdentifier;
+ }
+
public boolean isTel() {
return mIsTel;
}
@@ -104,6 +110,10 @@
mIdentifier = identifier;
}
+ public void setExtendedIdentifier(String extendedIdentifier) {
+ mExtendedIdentifier = extendedIdentifier;
+ }
+
public void setIsTel(boolean isTel) {
mIsTel = isTel;
}
@@ -170,6 +180,8 @@
"com.android.server.companion.datatransfer.contextsync.extra.FACILITATOR_NAME";
private static final String EXTRA_FACILITATOR_ID =
"com.android.server.companion.datatransfer.contextsync.extra.FACILITATOR_ID";
+ private static final String EXTRA_FACILITATOR_EXT_ID =
+ "com.android.server.companion.datatransfer.contextsync.extra.FACILITATOR_EXT_ID";
private static final String EXTRA_STATUS =
"com.android.server.companion.datatransfer.contextsync.extra.STATUS";
private static final String EXTRA_DIRECTION =
@@ -192,7 +204,10 @@
call.setAppIcon(bundle.getByteArray(EXTRA_APP_ICON));
final String facilitatorName = bundle.getString(EXTRA_FACILITATOR_NAME);
final String facilitatorIdentifier = bundle.getString(EXTRA_FACILITATOR_ID);
- call.setFacilitator(new CallFacilitator(facilitatorName, facilitatorIdentifier));
+ final String facilitatorExtendedIdentifier =
+ bundle.getString(EXTRA_FACILITATOR_EXT_ID);
+ call.setFacilitator(new CallFacilitator(facilitatorName, facilitatorIdentifier,
+ facilitatorExtendedIdentifier));
call.setStatus(bundle.getInt(EXTRA_STATUS));
call.setDirection(bundle.getInt(EXTRA_DIRECTION));
call.setControls(new HashSet<>(bundle.getIntegerArrayList(EXTRA_CONTROLS)));
@@ -207,6 +222,7 @@
bundle.putByteArray(EXTRA_APP_ICON, mAppIcon);
bundle.putString(EXTRA_FACILITATOR_NAME, mFacilitator.getName());
bundle.putString(EXTRA_FACILITATOR_ID, mFacilitator.getIdentifier());
+ bundle.putString(EXTRA_FACILITATOR_EXT_ID, mFacilitator.getExtendedIdentifier());
bundle.putInt(EXTRA_STATUS, mStatus);
bundle.putInt(EXTRA_DIRECTION, mDirection);
bundle.putIntegerArrayList(EXTRA_CONTROLS, new ArrayList<>(mControls));
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
index e8392d2..2a50799 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
@@ -48,6 +48,7 @@
private final int mUserId;
@VisibleForTesting boolean mIsEnterprise;
private final String mCallingAppPackageName;
+ private final String mSerializedPhoneAccountHandle;
private String mCallingAppName;
private byte[] mCallingAppIcon;
private String mCallerDisplayName;
@@ -89,6 +90,8 @@
.equals(handle.getComponentName());
mCallingAppPackageName = handle != null
? callDetails.getAccountHandle().getComponentName().getPackageName() : "";
+ mSerializedPhoneAccountHandle = handle != null
+ ? handle.getId() + SEPARATOR + handle.getComponentName().flattenToString() : "";
mIsEnterprise = (callDetails.getCallProperties() & Call.Details.PROPERTY_ENTERPRISE_CALL)
== Call.Details.PROPERTY_ENTERPRISE_CALL;
final PackageManager packageManager = context.getPackageManager();
@@ -247,6 +250,10 @@
return mCallingAppPackageName;
}
+ public String getSerializedPhoneAccountHandle() {
+ return mSerializedPhoneAccountHandle;
+ }
+
/**
* Get a human-readable "caller id" to display as the origin of the call.
*
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index 3169459..9bd5af9 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -280,7 +280,7 @@
mCallFacilitators.add(
new CallMetadataSyncData.CallFacilitator(
defaultOutgoingTelAccount.getLabel().toString(),
- FACILITATOR_ID_SYSTEM));
+ FACILITATOR_ID_SYSTEM, FACILITATOR_ID_SYSTEM));
}
}
}
@@ -574,6 +574,10 @@
case (int) Telecom.CallFacilitator.IDENTIFIER:
facilitator.setIdentifier(pis.readString(Telecom.CallFacilitator.IDENTIFIER));
break;
+ case (int) Telecom.CallFacilitator.EXTENDED_IDENTIFIER:
+ facilitator.setExtendedIdentifier(
+ pis.readString(Telecom.CallFacilitator.EXTENDED_IDENTIFIER));
+ break;
default:
Slog.e(TAG, "Unhandled field in Facilitator:"
+ ProtoUtils.currentFieldToString(pis));
@@ -649,6 +653,8 @@
final long facilitatorToken = pos.start(Telecom.Call.Origin.FACILITATOR);
pos.write(Telecom.CallFacilitator.NAME, call.getCallingAppName());
pos.write(Telecom.CallFacilitator.IDENTIFIER, call.getCallingAppPackageName());
+ pos.write(Telecom.CallFacilitator.EXTENDED_IDENTIFIER,
+ call.getSerializedPhoneAccountHandle());
pos.end(facilitatorToken);
pos.end(originToken);
pos.write(Telecom.Call.STATUS, call.getStatus());
@@ -662,6 +668,8 @@
final long facilitatorsToken = pos.start(Telecom.FACILITATORS);
pos.write(Telecom.CallFacilitator.NAME, facilitator.getName());
pos.write(Telecom.CallFacilitator.IDENTIFIER, facilitator.getIdentifier());
+ pos.write(Telecom.CallFacilitator.EXTENDED_IDENTIFIER,
+ facilitator.getExtendedIdentifier());
pos.end(facilitatorsToken);
}
pos.end(telecomToken);
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index 5a3db4b..3cb9ac8 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -130,6 +130,7 @@
if (DEBUG) {
Slog.d(TAG, "Starting secure channel.");
}
+ mStopped = false;
new Thread(() -> {
try {
// 1. Wait for the next handshake message and process it.
@@ -185,6 +186,17 @@
}
/**
+ * Return true if the channel is currently inactive.
+ * The channel could have been stopped by either {@link SecureChannel#stop()} or by
+ * encountering a fatal error.
+ *
+ * @return true if the channel is currently inactive.
+ */
+ public boolean isStopped() {
+ return mStopped;
+ }
+
+ /**
* Start exchanging handshakes to create a secure layer asynchronously. When the handshake is
* completed successfully, then the {@link Callback#onSecureConnection()} will trigger. Any
* error that occurs during the handshake will be passed by {@link Callback#onError(Throwable)}.
@@ -290,6 +302,7 @@
try {
data = new byte[length];
} catch (OutOfMemoryError error) {
+ Streams.skipByReading(mInput, Long.MAX_VALUE);
throw new SecureChannelException("Payload is too large.", error);
}
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index bc537ac..41867f9 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -20,14 +20,10 @@
import android.annotation.NonNull;
import android.annotation.SuppressLint;
-import android.app.ActivityManagerInternal;
import android.companion.AssociationInfo;
import android.companion.IOnMessageReceivedListener;
import android.companion.IOnTransportsChangedListener;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Binder;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
@@ -36,7 +32,6 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
import com.android.server.companion.AssociationStore;
import java.io.FileDescriptor;
@@ -135,42 +130,14 @@
synchronized (mTransports) {
for (int i = 0; i < associationIds.length; i++) {
if (mTransports.contains(associationIds[i])) {
- try {
- mTransports.get(associationIds[i]).sendMessage(message, data);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to send message 0x" + Integer.toHexString(message)
- + " data length " + data.length + " to association "
- + associationIds[i]);
- }
+ mTransports.get(associationIds[i]).requestForResponse(message, data);
}
}
}
}
- /**
- * For the moment, we only offer transporting of system data to built-in
- * companion apps; future work will improve the security model to support
- * third-party companion apps.
- */
- private void enforceCallerCanTransportSystemData(String packageName, int userId) {
- try {
- final ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser(
- packageName, 0, userId);
- final int instrumentationUid = LocalServices.getService(ActivityManagerInternal.class)
- .getInstrumentationSourceUid(Binder.getCallingUid());
- if (!Build.isDebuggable() && !info.isSystemApp()
- && instrumentationUid == android.os.Process.INVALID_UID) {
- throw new SecurityException("Transporting of system data currently only available "
- + "to built-in companion apps or tests");
- }
- } catch (NameNotFoundException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
public void attachSystemDataTransport(String packageName, int userId, int associationId,
ParcelFileDescriptor fd) {
- enforceCallerCanTransportSystemData(packageName, userId);
synchronized (mTransports) {
if (mTransports.contains(associationId)) {
detachSystemDataTransport(packageName, userId, associationId);
@@ -184,7 +151,6 @@
}
public void detachSystemDataTransport(String packageName, int userId, int associationId) {
- enforceCallerCanTransportSystemData(packageName, userId);
synchronized (mTransports) {
final Transport transport = mTransports.get(associationId);
if (transport != null) {
@@ -240,6 +206,7 @@
}
addMessageListenersToTransport(transport);
+ transport.setOnTransportClosedListener(this::detachSystemDataTransport);
transport.start();
synchronized (mTransports) {
mTransports.put(associationId, transport);
@@ -317,4 +284,14 @@
transport.addListener(mMessageListeners.keyAt(i), mMessageListeners.valueAt(i));
}
}
+
+ void detachSystemDataTransport(Transport transport) {
+ int associationId = transport.mAssociationId;
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ if (association != null) {
+ detachSystemDataTransport(association.getPackageName(),
+ association.getUserId(),
+ association.getId());
+ }
+ }
}
diff --git a/services/companion/java/com/android/server/companion/transport/RawTransport.java b/services/companion/java/com/android/server/companion/transport/RawTransport.java
index e64509f..ca169aac 100644
--- a/services/companion/java/com/android/server/companion/transport/RawTransport.java
+++ b/services/companion/java/com/android/server/companion/transport/RawTransport.java
@@ -70,6 +70,8 @@
}
IoUtils.closeQuietly(mRemoteIn);
IoUtils.closeQuietly(mRemoteOut);
+
+ super.close();
}
@Override
diff --git a/services/companion/java/com/android/server/companion/transport/SecureTransport.java b/services/companion/java/com/android/server/companion/transport/SecureTransport.java
index 2d856b9..a0301a9 100644
--- a/services/companion/java/com/android/server/companion/transport/SecureTransport.java
+++ b/services/companion/java/com/android/server/companion/transport/SecureTransport.java
@@ -21,7 +21,6 @@
import android.os.ParcelFileDescriptor;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.securechannel.AttestationVerifier;
import com.android.server.companion.securechannel.SecureChannel;
@@ -35,7 +34,6 @@
private volatile boolean mShouldProcessRequests = false;
- @GuardedBy("mRequestQueue")
private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100);
SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) {
@@ -64,6 +62,8 @@
void close() {
mSecureChannel.close();
mShouldProcessRequests = false;
+
+ super.close();
}
@Override
@@ -81,13 +81,19 @@
}
// Queue up a message to send
- synchronized (mRequestQueue) {
+ try {
mRequestQueue.add(ByteBuffer.allocate(HEADER_LENGTH + data.length)
.putInt(message)
.putInt(sequence)
.putInt(data.length)
.put(data)
.array());
+ } catch (IllegalStateException e) {
+ // Request buffer can only be full if too many requests are being added or
+ // the request processing thread is dead. Assume latter and detach the transport.
+ Slog.w(TAG, "Failed to queue message 0x" + Integer.toHexString(message)
+ + " . Request buffer is full; detaching transport.", e);
+ close();
}
}
@@ -96,8 +102,8 @@
try {
mSecureChannel.establishSecureConnection();
} catch (Exception e) {
- Slog.w(TAG, "Failed to initiate secure channel handshake.", e);
- onError(e);
+ Slog.e(TAG, "Failed to initiate secure channel handshake.", e);
+ close();
}
}
@@ -108,17 +114,14 @@
// TODO: find a better way to handle incoming requests than a dedicated thread.
new Thread(() -> {
- try {
- while (mShouldProcessRequests) {
- synchronized (mRequestQueue) {
- byte[] request = mRequestQueue.poll();
- if (request != null) {
- mSecureChannel.sendSecureMessage(request);
- }
- }
+ while (mShouldProcessRequests) {
+ try {
+ byte[] request = mRequestQueue.take();
+ mSecureChannel.sendSecureMessage(request);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to send secure message.", e);
+ close();
}
- } catch (IOException e) {
- onError(e);
}
}).start();
}
@@ -135,13 +138,18 @@
try {
handleMessage(message, sequence, content);
} catch (IOException error) {
- onError(error);
+ // IOException won't be thrown here because a separate thread is handling
+ // the write operations inside onSecureConnection().
}
}
@Override
public void onError(Throwable error) {
- mShouldProcessRequests = false;
- Slog.e(TAG, error.getMessage(), error);
+ Slog.e(TAG, "Secure transport encountered an error.", error);
+
+ // If the channel was stopped as a result of the error, then detach itself.
+ if (mSecureChannel.isStopped()) {
+ close();
+ }
}
}
diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java
index 6ad6d3a..5af3b98 100644
--- a/services/companion/java/com/android/server/companion/transport/Transport.java
+++ b/services/companion/java/com/android/server/companion/transport/Transport.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.companion.IOnMessageReceivedListener;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -70,6 +69,8 @@
*/
private final Map<Integer, IOnMessageReceivedListener> mListeners;
+ private OnTransportClosedListener mOnTransportClosed;
+
private static boolean isRequest(int message) {
return (message & 0xFF000000) == 0x63000000;
}
@@ -120,20 +121,18 @@
abstract void stop();
/**
- * Stop listening to the incoming data and close the streams.
+ * Stop listening to the incoming data and close the streams. If a listener for closed event
+ * is set, then trigger it to assist with its clean-up.
*/
- abstract void close();
+ void close() {
+ if (mOnTransportClosed != null) {
+ mOnTransportClosed.onClosed(this);
+ }
+ }
protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
throws IOException;
- /**
- * Send a message.
- */
- public void sendMessage(int message, @NonNull byte[] data) throws IOException {
- sendMessage(message, mNextSequence.incrementAndGet(), data);
- }
-
public Future<byte[]> requestForResponse(int message, byte[] data) {
if (DEBUG) Slog.d(TAG, "Requesting for response");
final int sequence = mNextSequence.incrementAndGet();
@@ -188,12 +187,6 @@
break;
}
case MESSAGE_REQUEST_PERMISSION_RESTORE: {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
- && !Build.isDebuggable()) {
- Slog.w(TAG, "Restoring permissions only supported on watches");
- sendMessage(MESSAGE_RESPONSE_FAILURE, sequence, EmptyArray.BYTE);
- break;
- }
try {
callback(message, data);
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
@@ -247,4 +240,14 @@
}
}
}
+
+ void setOnTransportClosedListener(OnTransportClosedListener callback) {
+ this.mOnTransportClosed = callback;
+ }
+
+ // Interface to pass transport to the transport manager to assist with detachment.
+ @FunctionalInterface
+ interface OnTransportClosedListener {
+ void onClosed(Transport transport);
+ }
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 6b948bd..9355741 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -113,6 +113,8 @@
| DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
| DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
+ private static final String PERSISTENT_ID_PREFIX_CDM_ASSOCIATION = "companion:";
+
/**
* Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
*/
@@ -126,6 +128,7 @@
private final PendingTrampolineCallback mPendingTrampolineCallback;
private final int mOwnerUid;
private int mDeviceId;
+ private @Nullable String mPersistentDeviceId;
// Thou shall not hold the mVirtualDeviceLock over the mInputController calls.
// Holding the lock can lead to lock inversion with GlobalWindowManagerLock.
// 1. After display is created the window manager calls into VDM during construction
@@ -240,6 +243,7 @@
UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid);
mContext = context.createContextAsUser(ownerUserHandle, 0);
mAssociationInfo = associationInfo;
+ mPersistentDeviceId = PERSISTENT_ID_PREFIX_CDM_ASSOCIATION + associationInfo.getId();
mService = service;
mPendingTrampolineCallback = pendingTrampolineCallback;
mActivityListener = activityListener;
@@ -329,6 +333,12 @@
return mDeviceId;
}
+ /** Returns the unique device ID of this device. */
+ @Override // Binder call
+ public @Nullable String getPersistentDeviceId() {
+ return mPersistentDeviceId;
+ }
+
@Override // Binder call
public int getAssociationId() {
return mAssociationInfo.getId();
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index bc24cf3..bbe7289 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -396,7 +396,8 @@
for (int i = 0; i < mVirtualDevices.size(); i++) {
final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
virtualDevices.add(
- new VirtualDevice(device.getDeviceId(), device.getDeviceName()));
+ new VirtualDevice(device.getDeviceId(), device.getPersistentDeviceId(),
+ device.getDeviceName()));
}
}
return virtualDevices;
@@ -686,6 +687,17 @@
}
@Override
+ public int getAssociationIdForDevice(int deviceId) {
+ VirtualDeviceImpl virtualDevice;
+ synchronized (mVirtualDeviceManagerLock) {
+ virtualDevice = mVirtualDevices.get(deviceId);
+ }
+ return virtualDevice == null
+ ? VirtualDeviceManager.ASSOCIATION_ID_INVALID
+ : virtualDevice.getAssociationId();
+ }
+
+ @Override
public void registerVirtualDisplayListener(
@NonNull VirtualDisplayListener listener) {
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9869b75..846283c 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1383,4 +1383,17 @@
@Deprecated
public abstract void legacyReconcileSecondaryDexFiles(String packageName)
throws LegacyDexoptDisabledException;
+
+ /**
+ * Gets {@link PackageManager.DistractionRestriction restrictions} of the given
+ * packages of the given user.
+ *
+ * The corresponding element of the resulting array will be -1 if a given package doesn't exist.
+ *
+ * @param packageNames The packages under which to check.
+ * @param userId The user under which to check.
+ * @return an array of distracting restriction state in order of the given packages
+ */
+ public abstract int[] getDistractingPackageRestrictionsAsUser(
+ @NonNull String[] packageNames, int userId);
}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 6e2e5f7..c094c12 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -382,6 +382,14 @@
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
+
+ if (level <= LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS) {
+ // Disabling flag resets on master branch for trunk stable launch.
+ // TODO(b/287618292): Re-enable them after the trunk stable is launched and we
+ // figured out a way to reset flags without interfering with trunk development.
+ return;
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a641e85..c718d39 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2093,20 +2093,24 @@
}
}
- public void notifyDataActivity(int state) {
- notifyDataActivityForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state);
- }
-
- public void notifyDataActivityForSubscriber(int subId, int state) {
+ /**
+ * Send a notification to registrants about the data activity state.
+ *
+ * @param phoneId the phoneId carrying the data connection
+ * @param subId the subscriptionId for the data connection
+ * @param state indicates the latest data activity type
+ * e.g.,{@link TelephonyManager#DATA_ACTIVITY_IN}
+ *
+ */
+ public void notifyDataActivityForSubscriber(int phoneId, int subId, int state) {
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
+
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mDataActivity[phoneId] = state;
for (Record r : mRecords) {
- // Notify by correct subId.
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)
&& idMatch(r, subId, phoneId)) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 12de0d7..2f7c890 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -406,6 +406,8 @@
// allowlisted packageName.
ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
+ String mCachedDeviceProvisioningPackage;
+
// TODO: remove this after feature development is done
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -480,7 +482,8 @@
// (REASON_ALARM_MANAGER_ALARM_CLOCK), allow it to continue and do not stop it,
// even the app is background-restricted.
if (r.isForeground
- && r.mAllowStartForegroundAtEntering != REASON_ALARM_MANAGER_ALARM_CLOCK) {
+ && r.mAllowStartForegroundAtEntering != REASON_ALARM_MANAGER_ALARM_CLOCK
+ && !isDeviceProvisioningPackage(r.packageName)) {
toStop.add(r);
}
}
@@ -880,7 +883,8 @@
boolean forcedStandby = false;
if (bgLaunch
&& appRestrictedAnyInBackground(appUid, appPackageName)
- && !isTempAllowedByAlarmClock(appUid)) {
+ && !isTempAllowedByAlarmClock(appUid)
+ && !isDeviceProvisioningPackage(appPackageName)) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Forcing bg-only service start only for " + r.shortInstanceName
+ " : bgLaunch=" + bgLaunch + " callerFg=" + callerFg);
@@ -1926,6 +1930,9 @@
*/
private boolean isForegroundServiceAllowedInBackgroundRestricted(ProcessRecord app) {
final ProcessStateRecord state = app.mState;
+ if (isDeviceProvisioningPackage(app.info.packageName)) {
+ return true;
+ }
if (!state.isBackgroundRestricted()
|| state.getSetProcState() <= ActivityManager.PROCESS_STATE_BOUND_TOP) {
return true;
@@ -8405,4 +8412,13 @@
}
return results;
}
+
+ private boolean isDeviceProvisioningPackage(String packageName) {
+ if (mCachedDeviceProvisioningPackage == null) {
+ mCachedDeviceProvisioningPackage = mAm.mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceProvisioningPackage);
+ }
+ return mCachedDeviceProvisioningPackage != null
+ && mCachedDeviceProvisioningPackage.equals(packageName);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index c2a2423..9bf8bf4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -1349,7 +1349,7 @@
mService.initDropboxRateLimiter();
}
- private void loadDeviceConfigConstants() {
+ void loadDeviceConfigConstants() {
mOnDeviceConfigChangedListener.onPropertiesChanged(
DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
mOnDeviceConfigChangedForComponentAliasListener.onPropertiesChanged(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fb82490..2d7f5af 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1526,7 +1526,8 @@
*/
int mBootPhase;
- volatile boolean mDeterministicUidIdle = false;
+ @GuardedBy("this")
+ boolean mDeterministicUidIdle = false;
@VisibleForTesting
public WindowManagerService mWindowManager;
@@ -4579,14 +4580,8 @@
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
- app.mState.setCurAdj(ProcessList.INVALID_ADJ);
- app.mState.setSetAdj(ProcessList.INVALID_ADJ);
- app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
- mOomAdjuster.setAttachingSchedGroupLSP(app);
- app.mState.setForcingToImportant(null);
+ mOomAdjuster.setAttachingProcessStatesLSP(app);
clearProcessForegroundLocked(app);
- app.mState.setHasShownUi(false);
- app.mState.setCached(false);
app.setDebugging(false);
app.setKilledByAm(false);
app.setKilled(false);
@@ -4755,8 +4750,14 @@
app.makeActive(thread, mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
}
+ app.setPendingFinishAttach(true);
+
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
+
+ updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN);
+ checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
+
final long now = SystemClock.uptimeMillis();
synchronized (mAppProfiler.mProfilerLock) {
app.mProfile.setLastRequestedGc(now);
@@ -4772,8 +4773,6 @@
if (!mConstants.mEnableWaitForFinishAttachApplication) {
finishAttachApplicationInner(startSeq, callingUid, pid);
- } else {
- app.setPendingFinishAttach(true);
}
} catch (Exception e) {
// We need kill the process group here. (b/148588589)
@@ -8596,10 +8595,7 @@
t.traceEnd();
}
- t.traceBegin("showSystemReadyErrorDialogs");
- mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
- t.traceEnd();
-
+ mHandler.post(mAtmInternal::showSystemReadyErrorDialogsIfNeeded);
if (isBootingSystemUser) {
// Need to send the broadcasts for the system user here because
@@ -14463,6 +14459,8 @@
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " and its parent (if any) are stopped");
+ scheduleCanceledResultTo(resultToApp, resultTo, intent, userId,
+ brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
@@ -14534,6 +14532,8 @@
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
}
@@ -14767,6 +14767,8 @@
if (aInfo == null) {
Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+ " ssp=" + ssp + " data=" + data);
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
}
updateAssociationForApp(aInfo);
@@ -14852,6 +14854,8 @@
// Apps should now be using ShortcutManager.pinRequestShortcut().
Log.w(TAG, "Broadcast " + action
+ " no longer supported. It will not be delivered.");
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
case Intent.ACTION_PRE_BOOT_COMPLETED:
timeoutExempt = true;
@@ -14859,6 +14863,8 @@
case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
callerPackage)) {
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
// Returning success seems to be the pattern here
return ActivityManager.BROADCAST_SUCCESS;
}
@@ -14893,6 +14899,8 @@
if (requiredPermissions != null && requiredPermissions.length > 0) {
Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permissions " + Arrays.toString(requiredPermissions));
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
@@ -15144,6 +15152,33 @@
}
@GuardedBy("this")
+ private void scheduleCanceledResultTo(ProcessRecord resultToApp, IIntentReceiver resultTo,
+ Intent intent, int userId, BroadcastOptions options, int callingUid,
+ String callingPackage) {
+ if (resultTo == null) {
+ return;
+ }
+ final ProcessRecord app = resultToApp;
+ final IApplicationThread thread = (app != null) ? app.getOnewayThread() : null;
+ if (thread != null) {
+ try {
+ final boolean shareIdentity = (options != null && options.isShareIdentityEnabled());
+ thread.scheduleRegisteredReceiver(
+ resultTo, intent, Activity.RESULT_CANCELED, null, null,
+ false, false, true, userId, app.mState.getReportedProcState(),
+ shareIdentity ? callingUid : Process.INVALID_UID,
+ shareIdentity ? callingPackage : null);
+ } catch (RemoteException e) {
+ final String msg = "Failed to schedule result of " + intent + " via "
+ + app + ": " + e;
+ app.killLocked("Can't schedule resultTo", ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
+ Slog.d(TAG, msg);
+ }
+ }
+ }
+
+ @GuardedBy("this")
private int getRealProcessStateLocked(ProcessRecord app, int pid) {
if (app == null) {
synchronized (mPidsSelfLocked) {
@@ -16512,7 +16547,9 @@
@Override
public void setDeterministicUidIdle(boolean deterministic) {
- mDeterministicUidIdle = deterministic;
+ synchronized (this) {
+ mDeterministicUidIdle = deterministic;
+ }
}
/** Make the currently active UIDs idle after a certain grace period. */
@@ -17286,6 +17323,12 @@
}
}
+ void onProcessFreezableChangedLocked(ProcessRecord app) {
+ if (mEnableModernQueue) {
+ mBroadcastQueues[0].onProcessFreezableChangedLocked(app);
+ }
+ }
+
@VisibleForTesting
public final class LocalService extends ActivityManagerInternal
implements ActivityManagerLocal {
@@ -18997,25 +19040,27 @@
// too quickly in parallel below
pingCount.incrementAndGet();
- synchronized (mProcLock) {
- final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
- mProcessList.getProcessNamesLOSP().getMap();
- final int numProc = pmap.size();
- for (int iProc = 0; iProc < numProc; iProc++) {
- final SparseArray<ProcessRecord> apps = pmap.valueAt(iProc);
- for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) {
- final ProcessRecord app = apps.valueAt(iApp);
- final IApplicationThread thread = app.getOnewayThread();
- if (thread != null) {
- mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app,
- CachedAppOptimizer.UNFREEZE_REASON_PING);
- pingCount.incrementAndGet();
- try {
- thread.schedulePing(pongCallback);
- } catch (RemoteException ignored) {
- // When we failed to ping remote process, pretend as
- // if we received the expected pong
- pongCallback.sendResult(null);
+ synchronized (ActivityManagerService.this) {
+ synchronized (mProcLock) {
+ final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
+ mProcessList.getProcessNamesLOSP().getMap();
+ final int numProc = pmap.size();
+ for (int iProc = 0; iProc < numProc; iProc++) {
+ final SparseArray<ProcessRecord> apps = pmap.valueAt(iProc);
+ for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) {
+ final ProcessRecord app = apps.valueAt(iApp);
+ final IApplicationThread thread = app.getOnewayThread();
+ if (thread != null) {
+ mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app,
+ CachedAppOptimizer.UNFREEZE_REASON_PING);
+ pingCount.incrementAndGet();
+ try {
+ thread.schedulePing(pongCallback);
+ } catch (RemoteException ignored) {
+ // When we failed to ping remote process, pretend as
+ // if we received the expected pong
+ pongCallback.sendResult(null);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5be3383..c0ac1f8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -931,8 +931,8 @@
final int result = mInterface.broadcastIntentWithFeature(null, null, intent, null,
receiver, 0, null, null, requiredPermissions, null, null,
android.app.AppOpsManager.OP_NONE, bundle, true, false, mUserId);
- Slogf.i(TAG, "Broadcasted %s: " + result, intent);
- if (!mAsync) {
+ Slogf.i(TAG, "Enqueued broadcast %s: " + result, intent);
+ if (result == ActivityManager.BROADCAST_SUCCESS && !mAsync) {
receiver.waitForFinish();
}
return 0;
@@ -3702,14 +3702,11 @@
if (foregroundActivities) {
try {
int prcState = mIam.getUidProcessState(uid, "android");
- ProcessRecord topApp = mInternal.getTopApp();
- if (topApp == null) {
- mPw.println("No top app found");
+
+ if (prcState == ProcessStateEnum.TOP) {
+ mPw.println("New foreground process: " + pid);
} else {
- int topPid = topApp.getPid();
- if (prcState == ProcessStateEnum.TOP && topPid == pid) {
- mPw.println("New foreground process: " + pid);
- }
+ mPw.println("No top app found");
}
mPw.flush();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index c2326f6..128bbdf 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -58,6 +58,7 @@
import android.os.BatteryUsageStatsQuery;
import android.os.PowerExemptionManager;
import android.os.PowerExemptionManager.ReasonCode;
+import android.os.Process;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
@@ -1975,15 +1976,15 @@
if (!mBgCurrentDrainHighThresholdByBgLocation) {
return false;
}
- final AppRestrictionController controller = mTracker.mAppRestrictionController;
- if (mInjector.getPermissionManagerServiceInternal().checkUidPermission(
- uid, ACCESS_BACKGROUND_LOCATION) == PERMISSION_GRANTED) {
+ if (mTracker.mContext.checkPermission(ACCESS_BACKGROUND_LOCATION,
+ Process.INVALID_PID, uid) == PERMISSION_GRANTED) {
return true;
}
if (!mBgCurrentDrainEventDurationBasedThresholdEnabled) {
return false;
}
final long since = Math.max(0, now - window);
+ final AppRestrictionController controller = mTracker.mAppRestrictionController;
final long locationDuration = controller.getForegroundServiceTotalDurationsSince(
uid, since, now, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
return locationDuration >= mBgCurrentDrainLocationMinDuration;
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 722d0d4..18a9153 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -43,6 +43,7 @@
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -292,8 +293,8 @@
mPermissionGranted = true;
return;
}
- mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
- .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
+ mPermissionGranted = mContext.checkPermission(mPermission, Process.INVALID_PID, mUid)
+ == PERMISSION_GRANTED;
}
void updateAppOps() {
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index a80ad59..0fcec6f 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
+import android.app.ActivityManager;
import android.app.BroadcastOptions;
import android.content.Intent;
import android.content.pm.ResolveInfo;
@@ -208,7 +209,7 @@
private boolean mLastDeferredStates;
private boolean mUidForeground;
- private boolean mUidCached;
+ private boolean mProcessFreezable;
private boolean mProcessInstrumented;
private boolean mProcessPersistent;
@@ -440,7 +441,7 @@
*/
@CheckResult
public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground,
- boolean uidCached) {
+ boolean processFreezable) {
this.app = app;
// Since we may have just changed our PID, invalidate cached strings
@@ -449,13 +450,13 @@
boolean didSomething = false;
if (app != null) {
- didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(uidForeground);
+ didSomething |= setProcessFreezable(processFreezable);
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
didSomething |= setProcessPersistent(app.isPersistent());
} else {
- didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(false);
+ didSomething |= setProcessFreezable(false);
didSomething |= setProcessInstrumented(false);
didSomething |= setProcessPersistent(false);
}
@@ -479,13 +480,13 @@
}
/**
- * Update if this process is in the "cached" state, typically signaling that
+ * Update if this process is in the "freezable" state, typically signaling that
* broadcast dispatch should be paused or delayed.
*/
@CheckResult
- private boolean setUidCached(boolean uidCached) {
- if (mUidCached != uidCached) {
- mUidCached = uidCached;
+ private boolean setProcessFreezable(boolean freezable) {
+ if (mProcessFreezable != freezable) {
+ mProcessFreezable = freezable;
invalidateRunnableAt();
return true;
} else {
@@ -1045,6 +1046,7 @@
static final int REASON_CONTAINS_MANIFEST = 17;
static final int REASON_FOREGROUND = 18;
static final int REASON_CORE_UID = 19;
+ static final int REASON_TOP_PROCESS = 20;
@IntDef(flag = false, prefix = { "REASON_" }, value = {
REASON_EMPTY,
@@ -1066,6 +1068,7 @@
REASON_CONTAINS_MANIFEST,
REASON_FOREGROUND,
REASON_CORE_UID,
+ REASON_TOP_PROCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Reason {}
@@ -1091,6 +1094,7 @@
case REASON_CONTAINS_MANIFEST: return "CONTAINS_MANIFEST";
case REASON_FOREGROUND: return "FOREGROUND";
case REASON_CORE_UID: return "CORE_UID";
+ case REASON_TOP_PROCESS: return "TOP_PROCESS";
default: return Integer.toString(reason);
}
}
@@ -1132,6 +1136,11 @@
} else if (mUidForeground) {
mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS;
mRunnableAtReason = REASON_FOREGROUND;
+ } else if (app != null && app.getSetProcState() == ActivityManager.PROCESS_STATE_TOP) {
+ // TODO (b/287676625): Use a callback to check when a process goes in and out of
+ // the TOP state.
+ mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS;
+ mRunnableAtReason = REASON_TOP_PROCESS;
} else if (mProcessPersistent) {
mRunnableAt = runnableAt + constants.DELAY_PERSISTENT_PROC_MILLIS;
mRunnableAtReason = REASON_PERSISTENT;
@@ -1150,7 +1159,7 @@
} else if (mCountManifest > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_MANIFEST;
- } else if (mUidCached) {
+ } else if (mProcessFreezable) {
if (r.deferUntilActive) {
// All enqueued broadcasts are deferrable, defer
if (mCountDeferred == mCountEnqueued) {
@@ -1220,7 +1229,7 @@
// When all we have pending is deferred broadcasts, and we're cached,
// then we want everything to be marked deferred
final boolean wantDeferredStates = (mCountDeferred > 0)
- && (mCountDeferred == mCountEnqueued) && mUidCached;
+ && (mCountDeferred == mCountEnqueued) && mProcessFreezable;
if (mLastDeferredStates != wantDeferredStates) {
mLastDeferredStates = wantDeferredStates;
@@ -1407,9 +1416,9 @@
if (mUidForeground) {
sb.append("FG");
}
- if (mUidCached) {
+ if (mProcessFreezable) {
if (sb.length() > 0) sb.append("|");
- sb.append("CACHED");
+ sb.append("FRZ");
}
if (mProcessInstrumented) {
if (sb.length() > 0) sb.append("|");
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index e38a2ee..c1f1dfd 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -174,6 +174,13 @@
public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app);
/**
+ * Signal from OS internals that the given process is in a freezable state and will be
+ * frozen soon after.
+ */
+ @GuardedBy("mService")
+ public abstract void onProcessFreezableChangedLocked(@NonNull ProcessRecord app);
+
+ /**
* Signal from OS internals that the given package (or some subset of that
* package) has been disabled or uninstalled, and that any pending
* broadcasts should be cleaned up.
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index f13dc89..127c5b3 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -466,6 +466,10 @@
skipCurrentOrPendingReceiverLocked(app);
}
+ public void onProcessFreezableChangedLocked(ProcessRecord app) {
+ // Not supported; ignore
+ }
+
public boolean sendPendingBroadcastsLocked(ProcessRecord app)
throws BroadcastDeliveryFailedException {
boolean didSomething = false;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5a81e2a..f5e2eb5 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -232,16 +232,6 @@
@GuardedBy("mService")
private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
- /**
- * Map from UID to its last known "cached" state.
- * <p>
- * We manually maintain this data structure since the lifecycle of
- * {@link ProcessRecord} and {@link BroadcastProcessQueue} can be
- * mismatched.
- */
- @GuardedBy("mService")
- private final SparseBooleanArray mUidCached = new SparseBooleanArray();
-
private final BroadcastConstants mConstants;
private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants;
@@ -258,6 +248,7 @@
private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4;
private static final int MSG_CHECK_HEALTH = 5;
private static final int MSG_CHECK_PENDING_COLD_START_VALIDITY = 6;
+ private static final int MSG_PROCESS_FREEZABLE_CHANGED = 7;
private void enqueueUpdateRunningList() {
mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
@@ -298,6 +289,12 @@
checkPendingColdStartValidity();
return true;
}
+ case MSG_PROCESS_FREEZABLE_CHANGED: {
+ synchronized (mService) {
+ refreshProcessQueueLocked((ProcessRecord) msg.obj);
+ }
+ return true;
+ }
}
return false;
};
@@ -458,7 +455,17 @@
updateWarmProcess(queue);
final boolean processWarm = queue.isProcessWarm();
- if (!processWarm) {
+ if (processWarm) {
+ mService.mOomAdjuster.unfreezeTemporarily(queue.app,
+ CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);
+ // The process could be killed as part of unfreezing. So, check again if it
+ // is still warm.
+ if (!queue.isProcessWarm()) {
+ queue = nextQueue;
+ enqueueUpdateRunningList();
+ continue;
+ }
+ } else {
// We only offer to run one cold-start at a time to preserve
// system resources; below we either claim that single slot or
// skip to look for another warm process
@@ -530,6 +537,7 @@
mRunningColdStart.reEnqueueActiveBroadcast();
demoteFromRunningLocked(mRunningColdStart);
clearRunningColdStart();
+ enqueueUpdateRunningList();
}
private void checkPendingColdStartValidity() {
@@ -564,6 +572,9 @@
@Override
public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app)
throws BroadcastDeliveryFailedException {
+ if (DEBUG_BROADCAST) {
+ logv("Process " + app + " is attached");
+ }
// Process records can be recycled, so always start by looking up the
// relevant per-process queue
final BroadcastProcessQueue queue = getProcessQueue(app);
@@ -613,18 +624,21 @@
@Override
public void onApplicationCleanupLocked(@NonNull ProcessRecord app) {
- // Process records can be recycled, so always start by looking up the
- // relevant per-process queue
- final BroadcastProcessQueue queue = getProcessQueue(app);
- if (queue != null) {
- setQueueProcess(queue, null);
+ if (DEBUG_BROADCAST) {
+ logv("Process " + app + " is cleaned up");
}
- if ((mRunningColdStart != null) && (mRunningColdStart == queue)) {
+ // This cleanup callback could be for an old process and not for the one we are waiting
+ // on, so explicitly check if this for the same ProcessRecord that a queue has.
+ final BroadcastProcessQueue queue = getProcessQueue(app);
+ if ((mRunningColdStart != null) && (mRunningColdStart == queue)
+ && mRunningColdStart.app == app) {
clearRunningColdStart();
}
- if (queue != null) {
+ if (queue != null && queue.app == app) {
+ setQueueProcess(queue, null);
+
// If queue was running a broadcast, fail it
if (queue.isActive()) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
@@ -656,6 +670,12 @@
}
@Override
+ public void onProcessFreezableChangedLocked(@NonNull ProcessRecord app) {
+ mLocalHandler.removeMessages(MSG_PROCESS_FREEZABLE_CHANGED, app);
+ mLocalHandler.sendMessage(mHandler.obtainMessage(MSG_PROCESS_FREEZABLE_CHANGED, app));
+ }
+
+ @Override
public int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app) {
final BroadcastProcessQueue queue = getProcessQueue(app);
if ((queue != null) && getRunningIndexOf(queue) >= 0) {
@@ -1073,6 +1093,7 @@
// If we were trying to deliver a manifest broadcast, throw the error as we need
// to try redelivering the broadcast to this receiver.
if (receiver instanceof ResolveInfo) {
+ mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
throw new BroadcastDeliveryFailedException(e);
}
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
@@ -1447,7 +1468,6 @@
};
broadcastPredicate = BROADCAST_PREDICATE_ANY;
- cleanupUserStateLocked(mUidCached, userId);
cleanupUserStateLocked(mUidForeground, userId);
}
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
@@ -1590,19 +1610,7 @@
refreshProcessQueuesLocked(uid);
}
}
-
- @Override
- public void onUidCachedChanged(int uid, boolean cached) {
- synchronized (mService) {
- if (cached) {
- mUidCached.put(uid, true);
- } else {
- mUidCached.delete(uid);
- }
- refreshProcessQueuesLocked(uid);
- }
- }
- }, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
+ }, ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.PROCESS_STATE_TOP, "android");
// Kick off periodic health checks
@@ -1794,10 +1802,9 @@
// warm via this operation, we're going to immediately promote it to
// be running, and any side effect of this operation will then apply
// after it's finished and is returned to the runnable list.
- queue.setProcessAndUidState(
- mService.getProcessRecordLocked(queue.processName, queue.uid),
- mUidForeground.get(queue.uid, false),
- mUidCached.get(queue.uid, false));
+ final ProcessRecord app = mService.getProcessRecordLocked(queue.processName, queue.uid);
+ queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
+ isProcessFreezable(app));
}
}
@@ -1809,11 +1816,21 @@
private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
@Nullable ProcessRecord app) {
if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
- mUidCached.get(queue.uid, false))) {
+ isProcessFreezable(app))) {
updateRunnableList(queue);
}
}
+ @GuardedBy("mService")
+ private boolean isProcessFreezable(@Nullable ProcessRecord app) {
+ if (app == null) {
+ return false;
+ }
+ synchronized (mService.mProcLock) {
+ return app.mOptRecord.isPendingFreeze() || app.mOptRecord.isFrozen();
+ }
+ }
+
/**
* Refresh the process queues with the latest process state so that runnableAt
* can be updated.
@@ -1831,6 +1848,20 @@
}
/**
+ * Refresh the process queue corresponding to {@code app} with the latest process state
+ * so that runnableAt can be updated.
+ */
+ @GuardedBy("mService")
+ private void refreshProcessQueueLocked(@NonNull ProcessRecord app) {
+ final BroadcastProcessQueue queue = getProcessQueue(app.processName, app.uid);
+ if (queue == null || queue.app == null || queue.app.getPid() != app.getPid()) {
+ return;
+ }
+ setQueueProcess(queue, queue.app);
+ enqueueUpdateRunningList();
+ }
+
+ /**
* Inform other parts of OS that the given broadcast queue has started
* running, typically for internal bookkeeping.
*/
@@ -2156,12 +2187,6 @@
ipw.decreaseIndent();
ipw.println();
- ipw.println("Cached UIDs:");
- ipw.increaseIndent();
- ipw.println(mUidCached);
- ipw.decreaseIndent();
- ipw.println();
-
ipw.println("Foreground UIDs:");
ipw.increaseIndent();
ipw.println(mUidForeground);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7773190..7e9283a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -123,7 +123,14 @@
"freeze_debounce_timeout";
@VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG =
"freeze_exempt_inst_pkg";
-
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED =
+ "freeze_binder_enabled";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR =
+ "freeze_binder_divisor";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET =
+ "freeze_binder_offset";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD =
+ "freeze_binder_threshold";
static final int UNFREEZE_REASON_NONE =
FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE;
@@ -237,8 +244,8 @@
@VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
// Defaults for phenotype flags.
- @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
- @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
+ @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true;
+ @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
@@ -257,7 +264,11 @@
@VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
@VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L;
- @VisibleForTesting static final Boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+ @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+ @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true;
+ @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4;
+ @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500;
+ @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000;
@VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor(
Settings.Global.CACHED_APPS_FREEZER_ENABLED);
@@ -393,6 +404,11 @@
updateFreezerDebounceTimeout();
} else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) {
updateFreezerExemptInstPkg();
+ } else if (KEY_FREEZER_BINDER_ENABLED.equals(name)
+ || KEY_FREEZER_BINDER_DIVISOR.equals(name)
+ || KEY_FREEZER_BINDER_THRESHOLD.equals(name)
+ || KEY_FREEZER_BINDER_OFFSET.equals(name)) {
+ updateFreezerBinderState();
}
}
}
@@ -455,6 +471,16 @@
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting final Set<Integer> mProcStateThrottle;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD;
+
+
// Handler on which compaction runs.
@VisibleForTesting
Handler mCompactionHandler;
@@ -759,6 +785,10 @@
pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
pw.println(" " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg);
+ pw.println(" " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled);
+ pw.println(" " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold);
+ pw.println(" " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor);
+ pw.println(" " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset);
synchronized (mProcLock) {
int size = mFrozenProcesses.size();
pw.println(" Apps frozen: " + size);
@@ -1264,6 +1294,26 @@
Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg);
}
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateFreezerBinderState() {
+ mFreezerBinderEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED);
+ mFreezerBinderDivisor = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR);
+ mFreezerBinderOffset = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET);
+ mFreezerBinderThreshold = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD);
+ Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled
+ + ", divisor=" + mFreezerBinderDivisor
+ + ", offset=" + mFreezerBinderOffset
+ + ", threshold=" + mFreezerBinderThreshold);
+ }
+
private boolean parseProcStateThrottle(String procStateThrottleString) {
String[] procStates = TextUtils.split(procStateThrottleString, ",");
mProcStateThrottle.clear();
@@ -1352,6 +1402,8 @@
}
}
}
+ reportProcessFreezableChangedLocked(app);
+ app.mOptRecord.setLastUsedTimeout(delayMillis);
mFreezeHandler.sendMessageDelayed(
mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
delayMillis);
@@ -1389,6 +1441,7 @@
uidRec.setFrozen(false);
postUidFrozenMessage(uidRec.getUid(), false);
}
+ reportProcessFreezableChangedLocked(app);
opt.setFreezerOverride(false);
if (pid == 0 || !opt.isFrozen()) {
@@ -1525,10 +1578,14 @@
opt.setPendingFreeze(false);
}
- UidRecord uidRec = app.getUidRecord();
- if (uidRec != null && uidRec.isFrozen()) {
- uidRec.setFrozen(false);
- postUidFrozenMessage(uidRec.getUid(), false);
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ final boolean isFrozen = uidRec.getNumOfProcs() > 1
+ && uidRec.areAllProcessesFrozen(app);
+ if (isFrozen != uidRec.isFrozen()) {
+ uidRec.setFrozen(isFrozen);
+ postUidFrozenMessage(uidRec.getUid(), isFrozen);
+ }
}
mFrozenProcesses.delete(app.getPid());
@@ -1537,15 +1594,22 @@
void onWakefulnessChanged(int wakefulness) {
if(wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
- // Remove any pending compaction we may have scheduled to happen while screen was off
- Slog.e(TAG_AM, "Cancel pending or running compactions as system is awake");
- cancelAllCompactions(CancelCompactReason.SCREEN_ON);
+ if (useCompaction()) {
+ // Remove any pending compaction we may have scheduled to happen while screen was
+ // off
+ cancelAllCompactions(CancelCompactReason.SCREEN_ON);
+ }
}
}
void cancelAllCompactions(CancelCompactReason reason) {
synchronized (mProcLock) {
while(!mPendingCompactionProcesses.isEmpty()) {
+ if (DEBUG_COMPACTION) {
+ Slog.e(TAG_AM,
+ "Cancel pending compaction as system is awake for process="
+ + mPendingCompactionProcesses.get(0).processName);
+ }
cancelCompactionForProcess(mPendingCompactionProcesses.get(0), reason);
}
mPendingCompactionProcesses.clear();
@@ -2066,6 +2130,11 @@
0, uidObj));
}
+ @GuardedBy("mAm")
+ private void reportProcessFreezableChangedLocked(ProcessRecord app) {
+ mAm.onProcessFreezableChangedLocked(app);
+ }
+
private final class FreezeHandler extends Handler implements
ProcLocksReader.ProcLocksReaderCallback {
private FreezeHandler() {
@@ -2075,7 +2144,7 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case SET_FROZEN_PROCESS_MSG:
+ case SET_FROZEN_PROCESS_MSG: {
ProcessRecord proc = (ProcessRecord) msg.obj;
synchronized (mAm) {
freezeProcess(proc);
@@ -2085,8 +2154,8 @@
removeMessages(DEADLOCK_WATCHDOG_MSG);
sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
}
- break;
- case REPORT_UNFREEZE_MSG:
+ } break;
+ case REPORT_UNFREEZE_MSG: {
int pid = msg.arg1;
int frozenDuration = msg.arg2;
Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj;
@@ -2094,13 +2163,13 @@
int reason = obj.second;
reportUnfreeze(pid, frozenDuration, processName, reason);
- break;
- case UID_FROZEN_STATE_CHANGED_MSG:
+ } break;
+ case UID_FROZEN_STATE_CHANGED_MSG: {
final boolean frozen = (msg.arg1 == 1);
final int uid = (int) msg.obj;
reportOneUidFrozenStateChanged(uid, frozen);
- break;
- case DEADLOCK_WATCHDOG_MSG:
+ } break;
+ case DEADLOCK_WATCHDOG_MSG: {
try {
// post-check to prevent deadlock
if (DEBUG_FREEZER) {
@@ -2110,19 +2179,61 @@
} catch (IOException e) {
Slog.w(TAG_AM, "Unable to check file locks");
}
- break;
+ } break;
default:
return;
}
}
@GuardedBy({"mAm", "mProcLock"})
- private void rescheduleFreeze(final ProcessRecord proc, final String reason,
- @UnfreezeReason int reasonCode) {
+ private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) {
+ if (!mFreezerBinderEnabled) {
+ // Just reschedule indefinitely.
+ unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+ freezeAppAsyncLSP(proc);
+ return;
+ }
+ /*
+ * This handles the case where a process couldn't be frozen due to pending binder
+ * transactions. In order to prevent apps from avoiding the freezer by spamming binder
+ * transactions, there is an exponential decrease in freezer retry times plus a random
+ * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a
+ * threshold, we assume that the app is spamming binder calls and can never be frozen,
+ * and we will then crash the app.
+ */
+ if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) {
+ // We've given the app plenty of chances, assume broken. Time to die.
+ Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: "
+ + proc.getPid() + " " + proc.processName);
+ mAm.mHandler.post(() -> {
+ synchronized (mAm) {
+ // Crash regardless of procstate in case the app has found another way
+ // to abuse oom_adj
+ if (proc.getThread() == null) {
+ return;
+ }
+ proc.killLocked("excessive binder traffic during cached",
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
+ true);
+ }
+ });
+ return;
+ }
+
+ long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor;
+ // range is [-mFreezerBinderOffset, +mFreezerBinderOffset]
+ int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset;
+ timeout = Math.max(timeout + offset, mFreezerBinderThreshold);
+
Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
- + " " + proc.processName + " (" + reason + ")");
- unfreezeAppLSP(proc, reasonCode);
- freezeAppAsyncLSP(proc);
+ + " " + proc.processName + " (" + reason + "), timeout=" + timeout);
+ Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK,
+ "Reschedule freeze " + proc.processName + ":" + proc.getPid()
+ + " timeout=" + timeout + ", reason=" + reason);
+
+ unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+ freezeAppAsyncLSP(proc, timeout);
}
/**
@@ -2169,7 +2280,7 @@
// transactions that might be pending.
try {
if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) {
- rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS);
+ handleBinderFreezerFailure(proc, "outstanding txns");
return;
}
} catch (RuntimeException e) {
@@ -2230,7 +2341,7 @@
if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) {
synchronized (mProcLock) {
- rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS);
+ handleBinderFreezerFailure(proc, "new pending txns");
}
return;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 764bbe8..e51fc0a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1009,7 +1009,6 @@
mCacheOomRanker.reRankLruCachedAppsLSP(mProcessList.getLruProcessesLSP(),
mProcessList.getLruProcessServiceStartLOSP());
}
- assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
if (computeClients) { // There won't be cycles if we didn't compute clients above.
// Cycle strategy:
@@ -1034,7 +1033,7 @@
ProcessRecord app = activeProcesses.get(i);
final ProcessStateRecord state = app.mState;
if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) {
- if (computeOomAdjLSP(app, state.getCurRawAdj(), topApp, true, now,
+ if (computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now,
true, true)) {
retryCycles = true;
}
@@ -1044,6 +1043,8 @@
}
mProcessesInCycle.clear();
+ assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
+
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
@@ -1292,12 +1293,19 @@
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
- if (!app.isKilledByAm() && app.getThread() != null && !app.isPendingFinishAttach()) {
+ if (!app.isKilledByAm() && app.getThread() != null) {
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
applyOomAdjLSP(app, true, now, nowElapsed, oomAdjReason);
}
+ if (app.isPendingFinishAttach()) {
+ // Avoid trimming processes that are still initializing. If they aren't
+ // hosting any components yet because they may be unfairly killed.
+ // We however apply the oom scores set at #setAttachingProcessStatesLSP.
+ continue;
+ }
+
final ProcessServiceRecord psr = app.mServices;
// Count the number of process types.
switch (state.getCurProcState()) {
@@ -2805,6 +2813,18 @@
capability &= ~PROCESS_CAPABILITY_BFSL;
}
+
+ if (app.isPendingFinishAttach()) {
+ // If the app is still starting up. We reset the computations to the
+ // hardcoded values in setAttachingProcessStatesLSP. This ensures that the app keeps
+ // hard-coded default 'startup' oom scores while starting up. When it finishes startup,
+ // we'll recompute oom scores based on it's actual hosted compoenents.
+ setAttachingProcessStatesLSP(app);
+ state.setAdjSeq(mAdjSeq);
+ state.setCompletedAdjSeq(state.getAdjSeq());
+ return false;
+ }
+
// Do final modification to adj. Everything we do between here and applying
// the final setAdj must be done in this function, because we will also use
// it when computing the final cached adj later. Note that we don't need to
@@ -3242,8 +3262,11 @@
}
@GuardedBy({"mService", "mProcLock"})
- void setAttachingSchedGroupLSP(ProcessRecord app) {
+ void setAttachingProcessStatesLSP(ProcessRecord app) {
int initialSchedGroup = SCHED_GROUP_DEFAULT;
+ int initialProcState = PROCESS_STATE_CACHED_EMPTY;
+ int initialCapability = PROCESS_CAPABILITY_NONE;
+ boolean initialCached = true;
final ProcessStateRecord state = app.mState;
// If the process has been marked as foreground, it is starting as the top app (with
// Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
@@ -3259,13 +3282,24 @@
setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
}
initialSchedGroup = SCHED_GROUP_TOP_APP;
+ initialProcState = PROCESS_STATE_TOP;
+ initialCapability = PROCESS_CAPABILITY_ALL;
+ initialCached = false;
} catch (Exception e) {
Slog.w(TAG, "Failed to pre-set top priority to " + app + " " + e);
}
}
- state.setSetSchedGroup(initialSchedGroup);
state.setCurrentSchedulingGroup(initialSchedGroup);
+ state.setCurProcState(initialProcState);
+ state.setCurRawProcState(initialProcState);
+ state.setCurCapability(initialCapability);
+ state.setCached(initialCached);
+
+ state.setCurAdj(ProcessList.FOREGROUND_APP_ADJ);
+ state.setCurRawAdj(ProcessList.FOREGROUND_APP_ADJ);
+ state.setForcingToImportant(null);
+ state.setHasShownUi(false);
}
// ONLY used for unit testing in OomAdjusterTests.java
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index ffe5a6e..f5c5ea8 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -127,6 +127,12 @@
@GuardedBy("mProcLock")
private @UptimeMillisLong long mEarliestFreezableTimeMillis;
+ /**
+ * This is the most recently used timeout for freezing the app in millis
+ */
+ @GuardedBy("mProcLock")
+ private long mLastUsedTimeout;
+
@GuardedBy("mProcLock")
long getLastCompactTime() {
return mLastCompactTime;
@@ -282,6 +288,16 @@
}
@GuardedBy("mProcLock")
+ long getLastUsedTimeout() {
+ return mLastUsedTimeout;
+ }
+
+ @GuardedBy("mProcLock")
+ void setLastUsedTimeout(long lastUsedTimeout) {
+ mLastUsedTimeout = lastUsedTimeout;
+ }
+
+ @GuardedBy("mProcLock")
boolean isFreezeExempt() {
return mFreezeExempt;
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 267d246..f532122c1 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -674,6 +674,11 @@
return mState.getCurProcState();
}
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ int getSetProcState() {
+ return mState.getSetProcState();
+ }
+
@GuardedBy({"mService", "mProcLock"})
public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
mProfile.onProcessActive(thread, tracker);
@@ -1197,6 +1202,9 @@
"Killing " + toShortString() + " (adj " + mState.getSetAdj()
+ "): " + reason, info.uid);
}
+ // Since the process is getting killed, reset the freezable related state.
+ mOptRecord.setPendingFreeze(false);
+ mOptRecord.setFrozen(false);
if (mPid > 0) {
mService.mProcessList.noteAppKill(this, reasonCode, subReason, description);
EventLog.writeEvent(EventLogTags.AM_KILL,
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index d4fd830..fc3d04f 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -229,7 +229,7 @@
firstPidEnd = new File(tracesFile).length();
}
// Append the Durations/latency comma separated array after the first PID.
- if (latencyTracker != null) {
+ if (firstPidTempDumpCopied && latencyTracker != null) {
appendtoANRFile(tracesFile,
latencyTracker.dumpAsCommaSeparatedArrayWithHeader());
}
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 993088e..4329afc 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -345,21 +345,32 @@
}
/**
+ * Check whether all processes in the Uid are frozen.
+ *
+ * @param excluding Skip this process record during the check.
* @return true if all processes in the Uid are frozen, false otherwise.
*/
@GuardedBy(anyOf = {"mService", "mProcLock"})
- public boolean areAllProcessesFrozen() {
+ public boolean areAllProcessesFrozen(ProcessRecord excluding) {
for (int i = mProcRecords.size() - 1; i >= 0; i--) {
final ProcessRecord app = mProcRecords.valueAt(i);
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
- if (!opt.isFrozen()) {
+ if (excluding != app && !opt.isFrozen()) {
return false;
}
}
return true;
}
+ /**
+ * @return true if all processes in the Uid are frozen, false otherwise.
+ */
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ public boolean areAllProcessesFrozen() {
+ return areAllProcessesFrozen(null);
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public void setFrozen(boolean frozen) {
mUidIsFrozen = frozen;
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 4e7865c..2d74564 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -88,8 +88,6 @@
UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
WindowManagerService windowManager) {
- // TODO(b/278857848): Make full screen user switcher cover top part of the screen as well.
- // This problem is seen only on phones, it works fine on tablets.
super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
mContext = context;
@@ -112,9 +110,12 @@
final WindowManager.LayoutParams attrs = window.getAttributes();
attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ attrs.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
window.setAttributes(attrs);
window.setBackgroundDrawableResource(android.R.color.transparent);
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ window.setDecorFitsSystemWindows(false);
}
void inflateContent() {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 84fe12e..e4dd4a4 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -30,6 +30,8 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
@@ -289,37 +291,38 @@
* @param on
* @param eventSource for logging purposes
*/
- /*package*/ void setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) {
+ /*package*/ void setSpeakerphoneOn(
+ IBinder cb, int uid, boolean on, boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid);
+ Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + uid);
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
- cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
- on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
+ cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
+ on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
}
/**
* Select device for use for communication use cases.
* @param cb Client binder for death detection
- * @param pid Client pid
+ * @param uid Client uid
* @param device Device selected or null to unselect.
* @param eventSource for logging purposes
*/
private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000;
- /*package*/ boolean setCommunicationDevice(
- IBinder cb, int pid, AudioDeviceInfo device, String eventSource) {
+ /*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device,
+ boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid);
+ Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid);
}
AudioDeviceAttributes deviceAttr =
(device != null) ? new AudioDeviceAttributes(device) : null;
- CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr,
- device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true);
+ CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, uid, deviceAttr,
+ device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true, isPrivileged);
postSetCommunicationDeviceForClient(deviceInfo);
boolean status;
synchronized (deviceInfo) {
@@ -353,7 +356,7 @@
Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
}
if (!deviceInfo.mOn) {
- CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid);
+ CommunicationRouteClient client = getCommunicationRouteClientForUid(deviceInfo.mUid);
if (client == null || (deviceInfo.mDevice != null
&& !deviceInfo.mDevice.equals(client.getDevice()))) {
return false;
@@ -361,22 +364,23 @@
}
AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
- setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device,
- deviceInfo.mScoAudioMode, deviceInfo.mEventSource);
+ setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mUid, device,
+ deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
return true;
}
@GuardedBy("mDeviceStateLock")
/*package*/ void setCommunicationRouteForClient(
- IBinder cb, int pid, AudioDeviceAttributes device,
- int scoAudioMode, String eventSource) {
+ IBinder cb, int uid, AudioDeviceAttributes device,
+ int scoAudioMode, boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
+ Log.v(TAG, "setCommunicationRouteForClient: device: " + device
+ + ", eventSource: " + eventSource);
}
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "setCommunicationRouteForClient for pid: " + pid
- + " device: " + device
+ "setCommunicationRouteForClient for uid: " + uid
+ + " device: " + device + " isPrivileged: " + isPrivileged
+ " from API: " + eventSource)).printLog(TAG));
final boolean wasBtScoRequested = isBluetoothScoRequested();
@@ -385,16 +389,18 @@
// Save previous client route in case of failure to start BT SCO audio
AudioDeviceAttributes prevClientDevice = null;
- client = getCommunicationRouteClientForPid(pid);
+ boolean prevPrivileged = false;
+ client = getCommunicationRouteClientForUid(uid);
if (client != null) {
prevClientDevice = client.getDevice();
+ prevPrivileged = client.isPrivileged();
}
if (device != null) {
- client = addCommunicationRouteClient(cb, pid, device);
+ client = addCommunicationRouteClient(cb, uid, device, isPrivileged);
if (client == null) {
- Log.w(TAG, "setCommunicationRouteForClient: could not add client for pid: "
- + pid + " and device: " + device);
+ Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: "
+ + uid + " and device: " + device);
}
} else {
client = removeCommunicationRouteClient(cb, true);
@@ -406,11 +412,11 @@
boolean isBtScoRequested = isBluetoothScoRequested();
if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) {
if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
- Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: "
- + pid);
+ Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: "
+ + uid);
// clean up or restore previous client selection
if (prevClientDevice != null) {
- addCommunicationRouteClient(cb, pid, prevClientDevice);
+ addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
} else {
removeCommunicationRouteClient(cb, true);
}
@@ -447,11 +453,12 @@
@GuardedBy("mDeviceStateLock")
private CommunicationRouteClient topCommunicationRouteClient() {
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
- if (crc.getPid() == mAudioModeOwner.mPid) {
+ if (crc.getUid() == mAudioModeOwner.mUid) {
return crc;
}
}
- if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) {
+ if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0
+ && mCommunicationRouteClients.get(0).isActive()) {
return mCommunicationRouteClients.get(0);
}
return null;
@@ -491,14 +498,48 @@
};
/*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+ return isValidCommunicationDeviceType(device.getType());
+ }
+
+ private static boolean isValidCommunicationDeviceType(int deviceType) {
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
- if (device.getType() == type) {
+ if (deviceType == type) {
return true;
}
}
return false;
}
+ /*package */
+ void postCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
+ if (!isValidCommunicationDeviceType(
+ AudioDeviceInfo.convertInternalDeviceToDeviceType(device.getInternalType()))) {
+ return;
+ }
+ sendLMsgNoDelay(MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL, SENDMSG_QUEUE, device);
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ void onCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "onCheckCommunicationDeviceRemoval device: " + device.toString());
+ }
+ for (CommunicationRouteClient crc : mCommunicationRouteClients) {
+ if (device.equals(crc.getDevice())) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "onCheckCommunicationDeviceRemoval removing client: "
+ + crc.toString());
+ }
+ // Cancelling the route for this client will remove it from the stack and update
+ // the communication route.
+ CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(
+ crc.getBinder(), crc.getUid(), device, false,
+ BtHelper.SCO_MODE_UNDEFINED, "onCheckCommunicationDeviceRemoval",
+ false, crc.isPrivileged());
+ postSetCommunicationDeviceForClient(deviceInfo);
+ }
+ }
+ }
/* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
AudioDeviceInfo[] allDevices =
@@ -1107,26 +1148,26 @@
sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
}
- /*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode,
- @NonNull String eventSource) {
+ /*package*/ void startBluetoothScoForClient(IBinder cb, int uid, int scoAudioMode,
+ boolean isPrivileged, @NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "startBluetoothScoForClient, pid: " + pid);
+ Log.v(TAG, "startBluetoothScoForClient, uid: " + uid);
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
- cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
- true, scoAudioMode, eventSource, false));
+ cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
+ true, scoAudioMode, eventSource, false, isPrivileged));
}
/*package*/ void stopBluetoothScoForClient(
- IBinder cb, int pid, @NonNull String eventSource) {
+ IBinder cb, int uid, boolean isPrivileged, @NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid);
+ Log.v(TAG, "stopBluetoothScoForClient, uid: " + uid);
}
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
- cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
- false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
+ cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
+ false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
}
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
@@ -1367,22 +1408,24 @@
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
- final int mPid; // Requester process ID
+ final int mUid; // Requester UID
final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset.
final boolean mOn; // true if setting, false if resetting
final int mScoAudioMode; // only used for SCO: requested audio mode
+ final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission
final @NonNull String mEventSource; // caller identifier for logging
boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent)
boolean mStatus = false; // completion status only used if mWaitForStatus is true
- CommunicationDeviceInfo(@NonNull IBinder cb, int pid,
+ CommunicationDeviceInfo(@NonNull IBinder cb, int uid,
@Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode,
- @NonNull String eventSource, boolean waitForStatus) {
+ @NonNull String eventSource, boolean waitForStatus, boolean isPrivileged) {
mCb = cb;
- mPid = pid;
+ mUid = uid;
mDevice = device;
mOn = on;
mScoAudioMode = scoAudioMode;
+ mIsPrivileged = isPrivileged;
mEventSource = eventSource;
mWaitForStatus = waitForStatus;
}
@@ -1401,16 +1444,17 @@
}
return mCb.equals(((CommunicationDeviceInfo) o).mCb)
- && mPid == ((CommunicationDeviceInfo) o).mPid;
+ && mUid == ((CommunicationDeviceInfo) o).mUid;
}
@Override
public String toString() {
return "CommunicationDeviceInfo mCb=" + mCb.toString()
- + " mPid=" + mPid
+ + " mUid=" + mUid
+ " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
+ " mOn=" + mOn
+ " mScoAudioMode=" + mScoAudioMode
+ + " mIsPrivileged=" + mIsPrivileged
+ " mEventSource=" + mEventSource
+ " mWaitForStatus=" + mWaitForStatus
+ " mStatus=" + mStatus;
@@ -1440,7 +1484,7 @@
}
}
- /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes,
+ /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
boolean connect, @Nullable BluetoothDevice btDevice) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.handleDeviceConnection(
@@ -1507,8 +1551,7 @@
pw.println("\n" + prefix + "Communication route clients:");
mCommunicationRouteClients.forEach((cl) -> {
- pw.println(" " + prefix + "pid: " + cl.getPid() + " device: "
- + cl.getDevice() + " cb: " + cl.getBinder()); });
+ pw.println(" " + prefix + cl.toString()); });
pw.println("\n" + prefix + "Computed Preferred communication device: "
+ preferredCommunicationDevice());
@@ -1850,6 +1893,15 @@
final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
} break;
+
+ case MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL: {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ onCheckCommunicationDeviceRemoval((AudioDeviceAttributes) msg.obj);
+ }
+ }
+ } break;
+
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1926,6 +1978,7 @@
private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49;
private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
+ private static final int MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL = 53;
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -2101,13 +2154,20 @@
private class CommunicationRouteClient implements IBinder.DeathRecipient {
private final IBinder mCb;
- private final int mPid;
+ private final int mUid;
+ private final boolean mIsPrivileged;
private AudioDeviceAttributes mDevice;
+ private boolean mPlaybackActive;
+ private boolean mRecordingActive;
- CommunicationRouteClient(IBinder cb, int pid, AudioDeviceAttributes device) {
+ CommunicationRouteClient(IBinder cb, int uid, AudioDeviceAttributes device,
+ boolean isPrivileged) {
mCb = cb;
- mPid = pid;
+ mUid = uid;
mDevice = device;
+ mIsPrivileged = isPrivileged;
+ mPlaybackActive = mAudioService.isPlaybackActiveForUid(uid);
+ mRecordingActive = mAudioService.isRecordingActiveForUid(uid);
}
public boolean registerDeathRecipient() {
@@ -2138,13 +2198,38 @@
return mCb;
}
- int getPid() {
- return mPid;
+ int getUid() {
+ return mUid;
+ }
+
+ boolean isPrivileged() {
+ return mIsPrivileged;
}
AudioDeviceAttributes getDevice() {
return mDevice;
}
+
+ public void setPlaybackActive(boolean active) {
+ mPlaybackActive = active;
+ }
+
+ public void setRecordingActive(boolean active) {
+ mRecordingActive = active;
+ }
+
+ public boolean isActive() {
+ return mIsPrivileged || mRecordingActive || mPlaybackActive;
+ }
+
+ @Override
+ public String toString() {
+ return "[CommunicationRouteClient: mUid: " + mUid
+ + " mDevice: " + mDevice.toString()
+ + " mIsPrivileged: " + mIsPrivileged
+ + " mPlaybackActive: " + mPlaybackActive
+ + " mRecordingActive: " + mRecordingActive + "]";
+ }
}
// @GuardedBy("mSetModeLock")
@@ -2154,8 +2239,9 @@
return;
}
Log.w(TAG, "Communication client died");
- setCommunicationRouteForClient(client.getBinder(), client.getPid(), null,
- BtHelper.SCO_MODE_UNDEFINED, "onCommunicationRouteClientDied");
+ setCommunicationRouteForClient(client.getBinder(), client.getUid(), null,
+ BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
+ "onCommunicationRouteClientDied");
}
/**
@@ -2242,8 +2328,8 @@
+ crc + " eventSource: " + eventSource);
}
if (crc != null) {
- setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
- BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
+ BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
}
}
@@ -2267,6 +2353,7 @@
dispatchCommunicationDevice();
}
+ @GuardedBy("mDeviceStateLock")
private CommunicationRouteClient removeCommunicationRouteClient(
IBinder cb, boolean unregister) {
for (CommunicationRouteClient cl : mCommunicationRouteClients) {
@@ -2282,11 +2369,12 @@
}
@GuardedBy("mDeviceStateLock")
- private CommunicationRouteClient addCommunicationRouteClient(
- IBinder cb, int pid, AudioDeviceAttributes device) {
+ private CommunicationRouteClient addCommunicationRouteClient(IBinder cb, int uid,
+ AudioDeviceAttributes device, boolean isPrivileged) {
// always insert new request at first position
removeCommunicationRouteClient(cb, true);
- CommunicationRouteClient client = new CommunicationRouteClient(cb, pid, device);
+ CommunicationRouteClient client =
+ new CommunicationRouteClient(cb, uid, device, isPrivileged);
if (client.registerDeathRecipient()) {
mCommunicationRouteClients.add(0, client);
return client;
@@ -2295,9 +2383,9 @@
}
@GuardedBy("mDeviceStateLock")
- private CommunicationRouteClient getCommunicationRouteClientForPid(int pid) {
+ private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) {
for (CommunicationRouteClient cl : mCommunicationRouteClients) {
- if (cl.getPid() == pid) {
+ if (cl.getUid() == uid) {
return cl;
}
}
@@ -2330,6 +2418,45 @@
return device;
}
+ void updateCommunicationRouteClientsActivity(
+ List<AudioPlaybackConfiguration> playbackConfigs,
+ List<AudioRecordingConfiguration> recordConfigs) {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ boolean updateCommunicationRoute = false;
+ for (CommunicationRouteClient crc : mCommunicationRouteClients) {
+ boolean wasActive = crc.isActive();
+ if (playbackConfigs != null) {
+ crc.setPlaybackActive(false);
+ for (AudioPlaybackConfiguration config : playbackConfigs) {
+ if (config.getClientUid() == crc.getUid()
+ && config.isActive()) {
+ crc.setPlaybackActive(true);
+ break;
+ }
+ }
+ }
+ if (recordConfigs != null) {
+ crc.setRecordingActive(false);
+ for (AudioRecordingConfiguration config : recordConfigs) {
+ if (config.getClientUid() == crc.getUid()
+ && !config.isClientSilenced()) {
+ crc.setRecordingActive(true);
+ break;
+ }
+ }
+ }
+ if (wasActive != crc.isActive()) {
+ updateCommunicationRoute = true;
+ }
+ }
+ if (updateCommunicationRoute) {
+ postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity");
+ }
+ }
+ }
+ }
+
@Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.getDeviceSensorUuid(device);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index ec85d57..b70e11d 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1199,11 +1199,16 @@
AudioDeviceInfo device = Stream.of(connectedDevices)
.filter(d -> d.getInternalType() == ada.getInternalType())
.filter(d -> (!AudioSystem.isBluetoothDevice(d.getInternalType())
- || (d.getAddress() == ada.getAddress())))
+ || (d.getAddress().equals(ada.getAddress()))))
.findFirst()
.orElse(null);
if (device == null) {
+ if (AudioService.DEBUG_DEVICES) {
+ Slog.i(TAG, "purgeRoles() removing device: " + ada.toString()
+ + ", for strategy: " + keyRole.first
+ + " and role: " + keyRole.second);
+ }
asi.deviceRoleAction(keyRole.first, keyRole.second, Arrays.asList(ada));
itDev.remove();
}
@@ -1240,8 +1245,9 @@
* @param btDevice the corresponding Bluetooth device when relevant.
* @return false if an error was reported by AudioSystem
*/
- /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
- boolean isForTesting, @Nullable BluetoothDevice btDevice) {
+ /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
+ boolean connect, boolean isForTesting,
+ @Nullable BluetoothDevice btDevice) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
@@ -1292,6 +1298,7 @@
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
+ mDeviceBroker.postCheckCommunicationDeviceRemoval(attributes);
status = true;
}
if (status) {
@@ -1796,8 +1803,9 @@
// device to remove was visible by APM, update APM
mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
- final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+ final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
@@ -1811,11 +1819,13 @@
"A2DP device addr=" + address + " made unavailable")).printLog(TAG));
}
mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/);
mmi.record();
updateBluetoothPreferredModes_l(null /*connectedDevice*/);
purgeDevicesRoles_l();
+ mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
}
@GuardedBy("mDevicesLock")
@@ -1850,12 +1860,14 @@
@GuardedBy("mDevicesLock")
private void makeA2dpSrcUnavailable(String address) {
- mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+ mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
+ mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
}
@GuardedBy("mDevicesLock")
@@ -1888,8 +1900,9 @@
@GuardedBy("mDevicesLock")
private void makeHearingAidDeviceUnavailable(String address) {
- mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_HEARING_AID, address),
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_HEARING_AID, address);
+ mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
@@ -1901,6 +1914,7 @@
.set(MediaMetrics.Property.DEVICE,
AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
.record();
+ mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
}
/**
@@ -1997,9 +2011,10 @@
@GuardedBy("mDevicesLock")
private void makeLeAudioDeviceUnavailableNow(String address, int device) {
+ AudioDeviceAttributes ada = null;
if (device != AudioSystem.DEVICE_NONE) {
- final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- device, address),
+ ada = new AudioDeviceAttributes(device, address);
+ final int res = AudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
@@ -2019,6 +2034,9 @@
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
updateBluetoothPreferredModes_l(null /*connectedDevice*/);
purgeDevicesRoles_l();
+ if (ada != null) {
+ mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
+ }
}
@GuardedBy("mDevicesLock")
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 67cb518..7404b19 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -355,7 +355,7 @@
private static final int MSG_SET_ALL_VOLUMES = 10;
private static final int MSG_UNLOAD_SOUND_EFFECTS = 15;
private static final int MSG_SYSTEM_READY = 16;
- private static final int MSG_UNMUTE_STREAM = 18;
+ private static final int MSG_UNMUTE_STREAM_ON_SINGLE_VOL_DEVICE = 18;
private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 19;
private static final int MSG_INDICATE_SYSTEM_READY = 20;
private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 21;
@@ -392,6 +392,7 @@
private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
private static final int MSG_LOWER_VOLUME_TO_RS1 = 53;
private static final int MSG_CONFIGURATION_CHANGED = 54;
+ private static final int MSG_BROADCAST_MASTER_MUTE = 55;
/** Messages handled by the {@link SoundDoseHelper}. */
/*package*/ static final int SAFE_MEDIA_VOLUME_MSG_START = 1000;
@@ -974,6 +975,9 @@
@GuardedBy("mSettingsLock")
private boolean mRttEnabled = false;
+ private AtomicBoolean mMasterMute = new AtomicBoolean(false);
+
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -2734,21 +2738,18 @@
}
final int currentUser = getCurrentUserId();
+ if (mUseFixedVolume) {
+ AudioSystem.setMasterVolume(1.0f);
+ }
+
// Check the current user restriction.
boolean masterMute =
mUserManagerInternal.getUserRestriction(currentUser,
UserManager.DISALLOW_UNMUTE_DEVICE)
|| mUserManagerInternal.getUserRestriction(currentUser,
UserManager.DISALLOW_ADJUST_VOLUME);
- if (mUseFixedVolume) {
- masterMute = false;
- AudioSystem.setMasterVolume(1.0f);
- }
- if (DEBUG_VOL) {
- Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
- }
- AudioSystem.setMasterMute(masterMute);
- broadcastMasterMuteStatus(masterMute);
+ setMasterMuteInternalNoCallerCheck(
+ masterMute, /* flags =*/ 0, currentUser, "readUserRestrictions");
mMicMuteFromRestrictions = mUserManagerInternal.getUserRestriction(
currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
@@ -3506,7 +3507,7 @@
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)
&& (keyEventMode != AudioDeviceVolumeManager.ADJUST_MODE_END)) {
- mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
+ mAudioHandler.removeMessages(MSG_UNMUTE_STREAM_ON_SINGLE_VOL_DEVICE);
if (isMuteAdjust && !mFullVolumeDevices.contains(device)) {
boolean state;
@@ -3533,8 +3534,9 @@
muteAliasStreams(streamTypeAlias, false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
- sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
- streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
+ sendMsg(mAudioHandler, MSG_UNMUTE_STREAM_ON_SINGLE_VOL_DEVICE,
+ SENDMSG_QUEUE, streamTypeAlias, flags, null,
+ UNMUTE_STREAM_DELAY);
}
}
}
@@ -3662,25 +3664,29 @@
* and aliases before mute change changed and after.
*/
private void muteAliasStreams(int streamAlias, boolean state) {
- synchronized (VolumeStreamState.class) {
- List<Integer> streamsToMute = new ArrayList<>();
- for (int stream = 0; stream < mStreamStates.length; stream++) {
- VolumeStreamState vss = mStreamStates[stream];
- if (streamAlias == mStreamVolumeAlias[stream] && vss.isMutable()) {
- if (!(mCameraSoundForced
- && (vss.getStreamType()
- == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
- boolean changed = vss.mute(state, /* apply= */ false, "muteAliasStreams");
- if (changed) {
- streamsToMute.add(stream);
+ // Locking mSettingsLock to avoid inversion when calling doMute -> updateVolumeGroupIndex
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ List<Integer> streamsToMute = new ArrayList<>();
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ VolumeStreamState vss = mStreamStates[stream];
+ if (streamAlias == mStreamVolumeAlias[stream] && vss.isMutable()) {
+ if (!(mCameraSoundForced
+ && (vss.getStreamType()
+ == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
+ boolean changed = vss.mute(state, /* apply= */ false,
+ "muteAliasStreams");
+ if (changed) {
+ streamsToMute.add(stream);
+ }
}
}
}
+ streamsToMute.forEach(streamToMute -> {
+ mStreamStates[streamToMute].doMute();
+ broadcastMuteSetting(streamToMute, state);
+ });
}
- streamsToMute.forEach(streamToMute -> {
- mStreamStates[streamToMute].doMute();
- broadcastMuteSetting(streamToMute, state);
- });
}
}
@@ -3693,20 +3699,27 @@
}
// Called after a delay when volume down is pressed while muted
- private void onUnmuteStream(int stream, int flags) {
+ private void onUnmuteStreamOnSingleVolDevice(int streamAlias, int flags) {
boolean wasMuted;
- synchronized (VolumeStreamState.class) {
- final VolumeStreamState streamState = mStreamStates[stream];
- // if unmuting causes a change, it was muted
- wasMuted = streamState.mute(false, "onUnmuteStream");
-
- final int device = getDeviceForStream(stream);
- final int index = streamState.getIndex(device);
- sendVolumeUpdate(stream, index, index, flags, device);
- }
- if (stream == AudioSystem.STREAM_MUSIC && wasMuted) {
- synchronized (mHdmiClientLock) {
- maybeSendSystemAudioStatusCommand(true);
+ // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute ->
+ // vss.updateVolumeGroupIndex
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ final VolumeStreamState streamState = mStreamStates[streamAlias];
+ // if unmuting causes a change, it was muted
+ wasMuted = streamState.mute(false, "onUnmuteStreamOnSingleVolDevice");
+ if (wasMuted) {
+ // Unmute all aliasted streams
+ muteAliasStreams(streamAlias, false);
+ }
+ final int device = getDeviceForStream(streamAlias);
+ final int index = streamState.getIndex(device);
+ sendVolumeUpdate(streamAlias, index, index, flags, device);
+ }
+ if (streamAlias == AudioSystem.STREAM_MUSIC && wasMuted) {
+ synchronized (mHdmiClientLock) {
+ maybeSendSystemAudioStatusCommand(true);
+ }
}
}
}
@@ -4250,22 +4263,41 @@
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period.
+ updateAudioModeHandlers(
+ configs /* playbackConfigs */, null /* recordConfigs */);
+ mDeviceBroker.updateCommunicationRouteClientsActivity(
+ configs /* playbackConfigs */, null /* recordConfigs */);
+ }
+
+ void updateAudioModeHandlers(List<AudioPlaybackConfiguration> playbackConfigs,
+ List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mDeviceBroker.mSetModeLock) {
boolean updateAudioMode = false;
int existingMsgPolicy = SENDMSG_QUEUE;
int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
boolean wasActive = h.isActive();
- h.setPlaybackActive(false);
- for (AudioPlaybackConfiguration config : configs) {
- final int usage = config.getAudioAttributes().getUsage();
- if (config.getClientUid() == h.getUid()
- && (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
+ if (playbackConfigs != null) {
+ h.setPlaybackActive(false);
+ for (AudioPlaybackConfiguration config : playbackConfigs) {
+ final int usage = config.getAudioAttributes().getUsage();
+ if (config.getClientUid() == h.getUid()
+ && (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
|| usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
- && config.getPlayerState()
- == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
- h.setPlaybackActive(true);
- break;
+ && config.isActive()) {
+ h.setPlaybackActive(true);
+ break;
+ }
+ }
+ }
+ if (recordConfigs != null) {
+ h.setRecordingActive(false);
+ for (AudioRecordingConfiguration config : recordConfigs) {
+ if (config.getClientUid() == h.getUid() && !config.isClientSilenced()
+ && config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
+ h.setRecordingActive(true);
+ break;
+ }
}
}
if (wasActive != h.isActive()) {
@@ -4303,38 +4335,10 @@
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period.
- synchronized (mDeviceBroker.mSetModeLock) {
- boolean updateAudioMode = false;
- int existingMsgPolicy = SENDMSG_QUEUE;
- int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
- for (SetModeDeathHandler h : mSetModeDeathHandlers) {
- boolean wasActive = h.isActive();
- h.setRecordingActive(false);
- for (AudioRecordingConfiguration config : configs) {
- if (config.getClientUid() == h.getUid()
- && config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
- h.setRecordingActive(true);
- break;
- }
- }
- if (wasActive != h.isActive()) {
- updateAudioMode = true;
- if (h.isActive() && h == getAudioModeOwnerHandler()) {
- existingMsgPolicy = SENDMSG_REPLACE;
- delay = 0;
- }
- }
- }
- if (updateAudioMode) {
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- existingMsgPolicy,
- AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(),
- mContext.getPackageName(),
- delay);
- }
- }
+ updateAudioModeHandlers(
+ null /* playbackConfigs */, configs /* recordConfigs */);
+ mDeviceBroker.updateCommunicationRouteClientsActivity(
+ null /* playbackConfigs */, configs /* recordConfigs */);
}
private void dumpAudioMode(PrintWriter pw) {
@@ -4750,16 +4754,10 @@
// UI update and Broadcast Intent
private void sendMasterMuteUpdate(boolean muted, int flags) {
mVolumeController.postMasterMuteChanged(updateFlagsForTvPlatform(flags));
- broadcastMasterMuteStatus(muted);
+ sendMsg(mAudioHandler, MSG_BROADCAST_MASTER_MUTE,
+ SENDMSG_QUEUE, muted ? 1 : 0, 0, null, 0);
}
- private void broadcastMasterMuteStatus(boolean muted) {
- Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
- | Intent.FLAG_RECEIVER_REPLACE_PENDING);
- sendStickyBroadcastToAll(intent);
- }
/**
* Sets the stream state's index, and posts a message to set system volume.
@@ -4926,18 +4924,21 @@
!= PackageManager.PERMISSION_GRANTED) {
return;
}
- setMasterMuteInternalNoCallerCheck(mute, flags, userId);
+ setMasterMuteInternalNoCallerCheck(mute, flags, userId, "setMasterMute");
}
- private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
+ private void setMasterMuteInternalNoCallerCheck(
+ boolean mute, int flags, int userId, String eventSource) {
if (DEBUG_VOL) {
- Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
+ Log.d(TAG, TextUtils.formatSimple("Master mute %s, %d, user=%d from %s",
+ mute, flags, userId, eventSource));
}
+
if (!isPlatformAutomotive() && mUseFixedVolume) {
// If using fixed volume, we don't mute.
// TODO: remove the isPlatformAutomotive check here.
// The isPlatformAutomotive check is added for safety but may not be necessary.
- return;
+ mute = false;
}
// For automotive,
// - the car service is always running as system user
@@ -4946,8 +4947,10 @@
// Therefore, the getCurrentUser() is always different to the foreground user.
if ((isPlatformAutomotive() && userId == UserHandle.USER_SYSTEM)
|| (getCurrentUserId() == userId)) {
- if (mute != AudioSystem.getMasterMute()) {
- AudioSystem.setMasterMute(mute);
+ if (mute != mMasterMute.getAndSet(mute)) {
+ sVolumeLogger.enqueue(new VolumeEvent(
+ VolumeEvent.VOL_MASTER_MUTE, mute));
+ mAudioSystem.setMasterMute(mute);
sendMasterMuteUpdate(mute, flags);
}
}
@@ -4955,7 +4958,7 @@
/** get global mute state. */
public boolean isMasterMute() {
- return AudioSystem.getMasterMute();
+ return mMasterMute.get();
}
@android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
@@ -6287,10 +6290,12 @@
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
.record();
}
-
+ final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity();
try {
- return mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource);
+ return mDeviceBroker.setCommunicationDevice(cb, uid, device, isPrivileged, eventSource);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6336,6 +6341,9 @@
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
}
+ final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED;
// for logging only
final int uid = Binder.getCallingUid();
@@ -6351,9 +6359,10 @@
.set(MediaMetrics.Property.STATE, on
? MediaMetrics.Value.ON : MediaMetrics.Value.OFF)
.record();
+
final long ident = Binder.clearCallingIdentity();
try {
- mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource);
+ mDeviceBroker.setSpeakerphoneOn(cb, uid, on, isPrivileged, eventSource);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6478,7 +6487,7 @@
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
BtHelper.scoAudioModeToString(scoAudioMode))
.record();
- startBluetoothScoInt(cb, pid, scoAudioMode, eventSource);
+ startBluetoothScoInt(cb, uid, scoAudioMode, eventSource);
}
@@ -6501,10 +6510,10 @@
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL))
.record();
- startBluetoothScoInt(cb, pid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource);
+ startBluetoothScoInt(cb, uid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource);
}
- void startBluetoothScoInt(IBinder cb, int pid, int scoAudioMode, @NonNull String eventSource) {
+ void startBluetoothScoInt(IBinder cb, int uid, int scoAudioMode, @NonNull String eventSource) {
MediaMetrics.Item mmi = new MediaMetrics.Item(MediaMetrics.Name.AUDIO_BLUETOOTH)
.set(MediaMetrics.Property.EVENT, "startBluetoothScoInt")
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
@@ -6515,9 +6524,13 @@
mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record();
return;
}
+ final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity();
try {
- mDeviceBroker.startBluetoothScoForClient(cb, pid, scoAudioMode, eventSource);
+ mDeviceBroker.startBluetoothScoForClient(
+ cb, uid, scoAudioMode, isPrivileged, eventSource);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6535,9 +6548,12 @@
final String eventSource = new StringBuilder("stopBluetoothSco()")
.append(") from u/pid:").append(uid).append("/")
.append(pid).toString();
+ final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity();
try {
- mDeviceBroker.stopBluetoothScoForClient(cb, pid, eventSource);
+ mDeviceBroker.stopBluetoothScoForClient(cb, uid, isPrivileged, eventSource);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -7605,7 +7621,11 @@
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
}
- mStreamStates[AudioSystem.STREAM_MUSIC].mute(false, "onAccessoryPlugMediaUnmute");
+ // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute ->
+ // vss.updateVolumeGroupIndex
+ synchronized (mSettingsLock) {
+ mStreamStates[AudioSystem.STREAM_MUSIC].mute(false, "onAccessoryPlugMediaUnmute");
+ }
}
}
@@ -7640,9 +7660,14 @@
continue;
}
}
- for (int i = 0; i < sVolumeGroupStates.size(); i++) {
- final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
- vgs.applyAllVolumes(/* userSwitch= */ false);
+
+ // need mSettingsLock for vgs.applyAllVolumes -> vss.setIndex which grabs this lock after
+ // VSS.class. Locking order needs to be preserved
+ synchronized (mSettingsLock) {
+ for (int i = 0; i < sVolumeGroupStates.size(); i++) {
+ final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
+ vgs.applyAllVolumes(/* userSwitch= */ false);
+ }
}
}
@@ -7679,9 +7704,14 @@
if (DEBUG_VOL) {
Log.v(TAG, "restoreVolumeGroups");
}
- for (int i = 0; i < sVolumeGroupStates.size(); i++) {
- final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
- vgs.applyAllVolumes(false/*userSwitch*/);
+
+ // need mSettingsLock for vgs.applyAllVolumes -> vss.setIndex which grabs this lock after
+ // VSS.class. Locking order needs to be preserved
+ synchronized (mSettingsLock) {
+ for (int i = 0; i < sVolumeGroupStates.size(); i++) {
+ final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
+ vgs.applyAllVolumes(false/*userSwitch*/);
+ }
}
}
@@ -7818,49 +7848,51 @@
}
public void adjustVolume(int direction, int flags) {
- synchronized (AudioService.VolumeStreamState.class) {
- int device = getDeviceForVolume();
- int previousIndex = getIndex(device);
- if (isMuteAdjust(direction) && !isMutable()) {
- // Non mutable volume group
- if (DEBUG_VOL) {
- Log.d(TAG, "invalid mute on unmutable volume group " + name());
- }
- return;
- }
- switch (direction) {
- case AudioManager.ADJUST_TOGGLE_MUTE: {
- // Note: If muted by volume 0, unmute will restore volume 0.
- mute(!mIsMuted);
- break;
- }
- case AudioManager.ADJUST_UNMUTE:
- // Note: If muted by volume 0, unmute will restore volume 0.
- mute(false);
- break;
- case AudioManager.ADJUST_MUTE:
- // May be already muted by setvolume 0, prevent from setting same value
- if (previousIndex != 0) {
- // bypass persist
- mute(true);
+ synchronized (mSettingsLock) {
+ synchronized (AudioService.VolumeStreamState.class) {
+ int device = getDeviceForVolume();
+ int previousIndex = getIndex(device);
+ if (isMuteAdjust(direction) && !isMutable()) {
+ // Non mutable volume group
+ if (DEBUG_VOL) {
+ Log.d(TAG, "invalid mute on unmutable volume group " + name());
}
- mIsMuted = true;
- break;
- case AudioManager.ADJUST_RAISE:
- // As for stream, RAISE during mute will increment the index
- setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags);
- break;
- case AudioManager.ADJUST_LOWER:
- // For stream, ADJUST_LOWER on a muted VSS is a no-op
- // If we decide to unmute on ADJUST_LOWER, cannot fallback on
- // adjustStreamVolume for group associated to legacy stream type
- if (isMuted() && previousIndex != 0) {
+ return;
+ }
+ switch (direction) {
+ case AudioManager.ADJUST_TOGGLE_MUTE: {
+ // Note: If muted by volume 0, unmute will restore volume 0.
+ mute(!mIsMuted);
+ break;
+ }
+ case AudioManager.ADJUST_UNMUTE:
+ // Note: If muted by volume 0, unmute will restore volume 0.
mute(false);
- } else {
- int newIndex = Math.max(previousIndex - 1, mIndexMin);
- setVolumeIndex(newIndex, device, flags);
- }
- break;
+ break;
+ case AudioManager.ADJUST_MUTE:
+ // May be already muted by setvolume 0, prevent from setting same value
+ if (previousIndex != 0) {
+ // bypass persist
+ mute(true);
+ }
+ mIsMuted = true;
+ break;
+ case AudioManager.ADJUST_RAISE:
+ // As for stream, RAISE during mute will increment the index
+ setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags);
+ break;
+ case AudioManager.ADJUST_LOWER:
+ // For stream, ADJUST_LOWER on a muted VSS is a no-op
+ // If we decide to unmute on ADJUST_LOWER, cannot fallback on
+ // adjustStreamVolume for group associated to legacy stream type
+ if (isMuted() && previousIndex != 0) {
+ mute(false);
+ } else {
+ int newIndex = Math.max(previousIndex - 1, mIndexMin);
+ setVolumeIndex(newIndex, device, flags);
+ }
+ break;
+ }
}
}
}
@@ -7872,11 +7904,13 @@
}
public void setVolumeIndex(int index, int flags) {
- synchronized (AudioService.VolumeStreamState.class) {
- if (mUseFixedVolume) {
- return;
+ synchronized (mSettingsLock) {
+ synchronized (AudioService.VolumeStreamState.class) {
+ if (mUseFixedVolume) {
+ return;
+ }
+ setVolumeIndex(index, getDeviceForVolume(), flags);
}
- setVolumeIndex(index, getDeviceForVolume(), flags);
}
}
@@ -8683,24 +8717,30 @@
// If associated to volume group, update group cache
private void updateVolumeGroupIndex(int device, boolean forceMuteState) {
- synchronized (VolumeStreamState.class) {
- if (mVolumeGroupState != null) {
- int groupIndex = (getIndex(device) + 5) / 10;
- if (DEBUG_VOL) {
- Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType
- + ", muted=" + mIsMuted + ", device=" + device + ", index="
- + getIndex(device) + ", group " + mVolumeGroupState.name()
- + " Muted=" + mVolumeGroupState.isMuted() + ", Index=" + groupIndex
- + ", forceMuteState=" + forceMuteState);
- }
- mVolumeGroupState.updateVolumeIndex(groupIndex, device);
- // Only propage mute of stream when applicable
- if (isMutable()) {
- // For call stream, align mute only when muted, not when index is set to 0
- mVolumeGroupState.mute(
- forceMuteState ? mIsMuted :
- (groupIndex == 0 && !isCallStream(mStreamType))
- || mIsMuted);
+ // need mSettingsLock when called from setIndex for vgs.mute -> vgs.applyAllVolumes ->
+ // vss.setIndex which grabs this lock after VSS.class. Locking order needs to be
+ // preserved
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ if (mVolumeGroupState != null) {
+ int groupIndex = (getIndex(device) + 5) / 10;
+ if (DEBUG_VOL) {
+ Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType
+ + ", muted=" + mIsMuted + ", device=" + device + ", index="
+ + getIndex(device) + ", group " + mVolumeGroupState.name()
+ + " Muted=" + mVolumeGroupState.isMuted() + ", Index="
+ + groupIndex + ", forceMuteState=" + forceMuteState);
+ }
+ mVolumeGroupState.updateVolumeIndex(groupIndex, device);
+ // Only propage mute of stream when applicable
+ if (isMutable()) {
+ // For call stream, align mute only when muted, not when index is set to
+ // 0
+ mVolumeGroupState.mute(
+ forceMuteState ? mIsMuted :
+ (groupIndex == 0 && !isCallStream(mStreamType))
+ || mIsMuted);
+ }
}
}
}
@@ -9191,8 +9231,8 @@
onAccessoryPlugMediaUnmute(msg.arg1);
break;
- case MSG_UNMUTE_STREAM:
- onUnmuteStream(msg.arg1, msg.arg2);
+ case MSG_UNMUTE_STREAM_ON_SINGLE_VOL_DEVICE:
+ onUnmuteStreamOnSingleVolDevice(msg.arg1, msg.arg2);
break;
case MSG_DYN_POLICY_MIX_STATE_UPDATE:
@@ -9234,6 +9274,10 @@
mSystemServer.sendMicrophoneMuteChangedIntent();
break;
+ case MSG_BROADCAST_MASTER_MUTE:
+ mSystemServer.broadcastMasterMuteStatus(msg.arg1 == 1);
+ break;
+
case MSG_CHECK_MODE_FOR_UID:
synchronized (mDeviceBroker.mSetModeLock) {
if (msg.obj == null) {
@@ -9246,8 +9290,8 @@
break;
}
boolean wasActive = h.isActive();
- h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid()));
- h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid()));
+ h.setPlaybackActive(isPlaybackActiveForUid(h.getUid()));
+ h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
mContext.getPackageName(), false /*force*/);
@@ -9631,7 +9675,8 @@
newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
|| newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
if (wasRestricted != isRestricted) {
- setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
+ setMasterMuteInternalNoCallerCheck(
+ isRestricted, /* flags =*/ 0, userId, "onUserRestrictionsChanged");
}
}
}
@@ -10832,6 +10877,10 @@
private void updateA11yVolumeAlias(boolean a11VolEnabled) {
if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
+ if (mIsSingleVolume) {
+ if (DEBUG_VOL) Log.d(TAG, "Accessibility volume is not set on single volume device");
+ return;
+ }
if (sIndependentA11yVolume != a11VolEnabled) {
sIndependentA11yVolume = a11VolEnabled;
// update the volume mapping scheme
@@ -11020,10 +11069,11 @@
pw.print(" mHdmiCecVolumeControlEnabled="); pw.println(mHdmiCecVolumeControlEnabled);
}
pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported);
- pw.print(" mic mute FromSwitch=" + mMicMuteFromSwitch
+ pw.println(" mic mute FromSwitch=" + mMicMuteFromSwitch
+ " FromRestrictions=" + mMicMuteFromRestrictions
+ " FromApi=" + mMicMuteFromApi
+ " from system=" + mMicMuteFromSystemCached);
+ pw.print(" mMasterMute="); pw.println(mMasterMute.get());
dumpAccessibilityServiceUids(pw);
dumpAssistantServicesUids(pw);
@@ -12341,6 +12391,16 @@
}
}
+ /* package */
+ boolean isPlaybackActiveForUid(int uid) {
+ return mPlaybackMonitor.isPlaybackActiveForUid(uid);
+ }
+
+ /* package */
+ boolean isRecordingActiveForUid(int uid) {
+ return mRecordMonitor.isRecordingActiveForUid(uid);
+ }
+
//======================
// Audio device management
//======================
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 6ebb42e..aac868f 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -228,6 +228,7 @@
static final int VOL_MUTE_STREAM_INT = 9;
static final int VOL_SET_LE_AUDIO_VOL = 10;
static final int VOL_ADJUST_GROUP_VOL = 11;
+ static final int VOL_MASTER_MUTE = 12;
final int mOp;
final int mStream;
@@ -321,6 +322,17 @@
logMetricEvent();
}
+ /** used for VOL_MASTER_MUTE */
+ VolumeEvent(int op, boolean state) {
+ mOp = op;
+ mStream = -1;
+ mVal1 = state ? 1 : 0;
+ mVal2 = 0;
+ mCaller = null;
+ mGroupName = null;
+ logMetricEvent();
+ }
+
/**
* Audio Analytics unique Id.
@@ -429,6 +441,9 @@
case VOL_MUTE_STREAM_INT:
// No value in logging metrics for this internal event
return;
+ case VOL_MASTER_MUTE:
+ // No value in logging metrics for this internal event
+ return;
default:
return;
}
@@ -510,6 +525,10 @@
.append(AudioSystem.streamToString(mStream))
.append(mVal1 == 1 ? ", muted)" : ", unmuted)")
.toString();
+ case VOL_MASTER_MUTE:
+ return new StringBuilder("Master mute:")
+ .append(mVal1 == 1 ? " muted)" : " unmuted)")
+ .toString();
default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
}
}
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 4343894..e70b649 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -685,6 +685,15 @@
}
/**
+ * Sets master mute state in audio flinger
+ * @param mute the mute state to set
+ * @return operation status
+ */
+ public int setMasterMute(boolean mute) {
+ return AudioSystem.setMasterMute(mute);
+ }
+
+ /**
* Part of AudioService dump
* @param pw
*/
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index c8a17e5..3560797 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -218,8 +218,8 @@
if (AudioService.DEBUG_VOL) {
AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent(
"setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp").printLog(TAG));
- return;
}
+ return;
}
if (!mAvrcpAbsVolSupported) {
AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent(
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 9fc0038..50ffbcb9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -812,8 +812,7 @@
return false;
}
final int reqUsage = requester.getAudioAttributes().getUsage();
- if ((reqUsage == AudioAttributes.USAGE_ASSISTANT)
- || (reqUsage == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) {
+ if (reqUsage == AudioAttributes.USAGE_ASSISTANT) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 652ea52..4332fdd 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -227,8 +227,8 @@
synchronized (mRecordStates) {
for (RecordingState state : mRecordStates) {
// Note: isActiveConfiguration() == true => state.getConfig() != null
- if (state.isActiveConfiguration()
- && state.getConfig().getClientUid() == uid) {
+ if (state.isActiveConfiguration() && state.getConfig().getClientUid() == uid
+ && !state.getConfig().isClientSilenced()) {
return true;
}
}
diff --git a/services/core/java/com/android/server/audio/SystemServerAdapter.java b/services/core/java/com/android/server/audio/SystemServerAdapter.java
index 22456bc..dfcd2e9 100644
--- a/services/core/java/com/android/server/audio/SystemServerAdapter.java
+++ b/services/core/java/com/android/server/audio/SystemServerAdapter.java
@@ -145,4 +145,18 @@
ActivityManager.broadcastStickyIntent(intent, profileId);
}
}
+
+ /*package*/ void broadcastMasterMuteStatus(boolean muted) {
+ Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 44e3d1e..e6f25cb 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -267,17 +267,30 @@
}
private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
- // If the caller requested STRONG, and the device contains both STRONG and non-STRONG
- // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
- // BIOMETRIC_INSUFFICIENT_STRENGTH error. Pretty sure we can always prioritize
- // BIOMETRIC_NOT_ENROLLED over any other error (unless of course its calculation is
- // wrong, in which case we should fix that instead).
+ Pair<BiometricSensor, Integer> sensorNotEnrolled = null;
+ Pair<BiometricSensor, Integer> sensorLockout = null;
for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) {
+ int status = pair.second;
+ if (status == BIOMETRIC_LOCKOUT_TIMED || status == BIOMETRIC_LOCKOUT_PERMANENT) {
+ sensorLockout = pair;
+ }
if (pair.second == BIOMETRIC_NOT_ENROLLED) {
- return pair;
+ sensorNotEnrolled = pair;
}
}
+ // If there is a sensor locked out, prioritize lockout over other sensor's error.
+ // See b/286923477.
+ if (sensorLockout != null) {
+ return sensorLockout;
+ }
+
+ // If the caller requested STRONG, and the device contains both STRONG and non-STRONG
+ // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
+ // BIOMETRIC_INSUFFICIENT_STRENGTH error.
+ if (sensorNotEnrolled != null) {
+ return sensorNotEnrolled;
+ }
return ineligibleSensors.get(0);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 46c77e8..aa6a0f1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -210,4 +210,8 @@
public boolean isInterruptable() {
return true;
}
+
+ public boolean isAlreadyCancelled() {
+ return mAlreadyCancelled;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 7fa4d6c..78c3808 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -268,6 +268,14 @@
return;
}
+ if (mCurrentOperation.isAcquisitionOperation()) {
+ AcquisitionClient client = (AcquisitionClient) mCurrentOperation.getClientMonitor();
+ if (client.isAlreadyCancelled()) {
+ mCurrentOperation.cancel(mHandler, mInternalCallback);
+ return;
+ }
+ }
+
if (mGestureAvailabilityDispatcher != null && mCurrentOperation.isAcquisitionOperation()) {
mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.getSensorId(), true /* active */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 2e1a363..1a682a9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -170,6 +170,12 @@
}
}
+ public void onUdfpsOverlayShown() throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onUdfpsOverlayShown();
+ }
+ }
+
// Face-specific callbacks for FaceManager only
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 7ae31b2..50d375c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -212,6 +212,8 @@
// 1) Authenticated == true
// 2) Error occurred
// 3) Authenticated == false
+ // 4) onLockout
+ // 5) onLockoutTimed
mCallback.onClientFinished(this, true /* success */);
}
@@ -304,11 +306,7 @@
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementTimedLockoutForUser(getTargetUserId());
- try {
- getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
+ onError(error, 0 /* vendorCode */);
}
@Override
@@ -323,10 +321,6 @@
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementPermanentLockoutForUser(getTargetUserId());
- try {
- getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
+ onError(error, 0 /* vendorCode */);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index d6b6f77..33ed63c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -149,6 +149,17 @@
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricContext biometricContext) {
+ this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
+ biometricContext, null /* daemon */);
+ }
+
+ @VisibleForTesting FaceProvider(@NonNull Context context,
+ @NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull SensorProps[] props,
+ @NonNull String halInstanceName,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull BiometricContext biometricContext,
+ IFace daemon) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
@@ -160,6 +171,7 @@
mTaskStackListener = new BiometricTaskStackListener();
mBiometricContext = biometricContext;
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
+ mDaemon = daemon;
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
@@ -475,7 +487,7 @@
BaseClientMonitor clientMonitor,
boolean success) {
mAuthSessionCoordinator.authEndedFor(userId, Utils.getCurrentStrength(sensorId),
- sensorId, requestId, success);
+ sensorId, requestId, client.wasAuthSuccessful());
}
});
});
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 ece35c5..ea6bb62 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
@@ -913,7 +913,6 @@
}
provider.onPointerDown(requestId, sensorId, pc);
}
-
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
@@ -929,17 +928,19 @@
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
- public void onUiReady(long requestId, int sensorId) {
- super.onUiReady_enforcePermission();
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event, long requestId,
+ int sensorId) {
+ super.onUdfpsUiEvent_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
- Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
+ Slog.w(TAG, "No matching provider for onUdfpsUiEvent, sensorId: " + sensorId);
return;
}
- provider.onUiReady(requestId, sensorId);
+ provider.onUdfpsUiEvent(event, requestId, sensorId);
}
+
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
@@ -1182,4 +1183,15 @@
}
}
}
+
+ void simulateVhalFingerDown() {
+ if (Utils.isVirtualEnabled(getContext())) {
+ Slog.i(TAG, "Simulate virtual HAL finger down event");
+ final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ if (provider != null) {
+ provider.second.simulateVhalFingerDown(UserHandle.getCallingUserId(),
+ provider.first);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
index 636413f..dc6a63f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
@@ -45,6 +45,8 @@
return doHelp();
case "sync":
return doSync();
+ case "fingerdown":
+ return doSimulateVhalFingerDown();
default:
getOutPrintWriter().println("Unrecognized command: " + cmd);
}
@@ -62,6 +64,8 @@
pw.println(" Print this help text.");
pw.println(" sync");
pw.println(" Sync enrollments now (virtualized sensors only).");
+ pw.println(" fingerdown");
+ pw.println(" Simulate finger down event (virtualized sensors only).");
}
private int doHelp() {
@@ -73,4 +77,9 @@
mService.syncEnrollmentsNow();
return 0;
}
+
+ private int doSimulateVhalFingerDown() {
+ mService.simulateVhalFingerDown();
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 004af2c..d70ca8c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -130,7 +130,7 @@
void onPointerUp(long requestId, int sensorId, PointerContext pc);
- void onUiReady(long requestId, int sensorId);
+ void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event, long requestId, int sensorId);
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
@@ -157,4 +157,11 @@
* @param sensorId sensor ID of the associated operation
*/
default void scheduleWatchdog(int sensorId) {}
+
+ /**
+ * Simulate fingerprint down touch event for virtual HAL
+ * @param userId user ID
+ * @param sensorId sensor ID
+ */
+ default void simulateVhalFingerDown(int userId, int sensorId) {};
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
index da7163a..dce0175 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors.fingerprint;
import android.hardware.biometrics.fingerprint.PointerContext;
+import android.hardware.fingerprint.FingerprintManager;
import com.android.server.biometrics.sensors.BaseClientMonitor;
@@ -28,6 +29,6 @@
public interface Udfps {
void onPointerDown(PointerContext pc);
void onPointerUp(PointerContext pc);
- void onUiReady();
+ void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event);
boolean isPointerDown();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 135eccf..ec1eeb1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -114,6 +114,11 @@
public void onUdfpsPointerUp(int sensorId) {
}
+
+ @Override
+ public void onUdfpsOverlayShown() {
+
+ }
};
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 2bfc239..3fc36b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -27,6 +27,7 @@
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlay;
@@ -363,9 +364,11 @@
}
@Override
- public void onUiReady() {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event) {
try {
- getFreshDaemon().getSession().onUiReady();
+ if (event == FingerprintManager.UDFPS_UI_READY) {
+ getFreshDaemon().getSession().onUiReady();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index c2ca78e..d35469c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -265,11 +265,20 @@
}
@Override
- public void onUiReady() {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event) {
try {
- getFreshDaemon().getSession().onUiReady();
+ switch (event) {
+ case FingerprintManager.UDFPS_UI_OVERLAY_SHOWN:
+ getListener().onUdfpsOverlayShown();
+ break;
+ case FingerprintManager.UDFPS_UI_READY:
+ getFreshDaemon().getSession().onUiReady();
+ break;
+ default:
+ Slog.w(TAG, "No matching event for onUdfpsUiEvent");
+ }
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to send UI ready", e);
+ Slog.e(TAG, "Unable to send onUdfpsUiEvent", e);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 58ece89..f8d2566 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -160,6 +160,17 @@
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
+ this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
+ gestureAvailabilityDispatcher, biometricContext, null /* daemon */);
+ }
+
+ @VisibleForTesting FingerprintProvider(@NonNull Context context,
+ @NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull SensorProps[] props, @NonNull String halInstanceName,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull BiometricContext biometricContext,
+ IFingerprint daemon) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
@@ -170,6 +181,7 @@
mTaskStackListener = new BiometricTaskStackListener();
mBiometricContext = biometricContext;
mAuthSessionCoordinator = mBiometricContext.getAuthSessionCoordinator();
+ mDaemon = daemon;
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
@@ -669,14 +681,15 @@
}
@Override
- public void onUiReady(long requestId, int sensorId) {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event, long requestId,
+ int sensorId) {
mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
requestId, (client) -> {
if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onUiReady received during client: " + client);
+ Slog.e(getTag(), "onUdfpsUiEvent received during client: " + client);
return;
}
- ((Udfps) client).onUiReady();
+ ((Udfps) client).onUdfpsUiEvent(event);
});
}
@@ -844,4 +857,18 @@
}
biometricScheduler.startWatchdog();
}
+
+ @Override
+ public void simulateVhalFingerDown(int userId, int sensorId) {
+ Slog.d(getTag(), "Simulate virtual HAL finger down event");
+ final AidlSession session = mFingerprintSensors.get(sensorId).getSessionForUser(userId);
+ final PointerContext pc = new PointerContext();
+ try {
+ session.getSession().onPointerDownWithContext(pc);
+ session.getSession().onUiReady();
+ session.getSession().onPointerUpWithContext(pc);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "failed hal operation ", e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 86a9f79..c20a9eb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -115,6 +115,11 @@
public void onUdfpsPointerUp(int sensorId) {
}
+
+ @Override
+ public void onUdfpsOverlayShown() {
+
+ }
};
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 9e6f4e4..1cbbf89 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -829,13 +829,14 @@
}
@Override
- public void onUiReady(long requestId, int sensorId) {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event, long requestId,
+ int sensorId) {
mScheduler.getCurrentClientIfMatches(requestId, (client) -> {
if (!(client instanceof Udfps)) {
- Slog.w(TAG, "onUiReady received during client: " + client);
+ Slog.w(TAG, "onUdfpsUiEvent received during client: " + client);
return;
}
- ((Udfps) client).onUiReady();
+ ((Udfps) client).onUdfpsUiEvent(event);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index d22aef8..2a62338 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -27,6 +27,7 @@
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlay;
@@ -273,7 +274,7 @@
}
@Override
- public void onUiReady() {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event) {
// Unsupported in HIDL.
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 362c820..ed0a201 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -25,6 +25,7 @@
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
@@ -130,7 +131,7 @@
}
@Override
- public void onUiReady() {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event) {
// Unsupported in HIDL.
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 78039ef..c2b7944 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -186,7 +186,7 @@
}
@Override
- public void onUiReady() {
+ public void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event) {
// Unsupported in HIDL.
}
}
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 4d12574..ee323f9 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -156,4 +156,14 @@
* @return the set of display ids for all VirtualDisplays owned by the device
*/
public abstract @NonNull ArraySet<Integer> getDisplayIdsForDevice(int deviceId);
+
+ /**
+ * Gets the CDM association ID for the VirtualDevice with the given device ID.
+ *
+ * @param deviceId which device we're asking about
+ * @return the CDM association ID for this device, or
+ * {@link android.companion.virtual.VirtualDeviceManager#ASSOCIATION_ID_INVALID} if no such
+ * association exists.
+ */
+ public abstract int getAssociationIdForDevice(int deviceId);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e85eee81..6b69e1c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1389,7 +1389,7 @@
}
// Check that the caller is authorized.
- enforceControlPermission();
+ enforceControlPermissionOrInternalCaller();
// Stop an existing always-on VPN from being dethroned by other apps.
if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 7ccfb44..d9cb299 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -515,7 +515,9 @@
private final SensorData mScreenOffBrightnessSensor = new SensorData();
// The details of the proximity sensor associated with this display.
- private final SensorData mProximitySensor = new SensorData();
+ // Is null when no sensor should be used for that display
+ @Nullable
+ private SensorData mProximitySensor = new SensorData();
private final List<RefreshRateLimitation> mRefreshRateLimitations =
new ArrayList<>(2 /*initialCapacity*/);
@@ -1337,7 +1339,8 @@
return mScreenOffBrightnessSensor;
}
- SensorData getProximitySensor() {
+ @Nullable
+ public SensorData getProximitySensor() {
return mProximitySensor;
}
@@ -2563,46 +2566,51 @@
private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) {
final SensorDetails sensorDetails = config.getLightSensor();
if (sensorDetails != null) {
- mAmbientLightSensor.type = sensorDetails.getType();
- mAmbientLightSensor.name = sensorDetails.getName();
- final RefreshRateRange rr = sensorDetails.getRefreshRate();
- if (rr != null) {
- mAmbientLightSensor.minRefreshRate = rr.getMinimum().floatValue();
- mAmbientLightSensor.maxRefreshRate = rr.getMaximum().floatValue();
- }
+ loadSensorData(sensorDetails, mAmbientLightSensor);
} else {
loadAmbientLightSensorFromConfigXml();
}
}
private void setProxSensorUnspecified() {
- mProximitySensor.name = null;
- mProximitySensor.type = null;
+ mProximitySensor = new SensorData();
}
private void loadScreenOffBrightnessSensorFromDdc(DisplayConfiguration config) {
final SensorDetails sensorDetails = config.getScreenOffBrightnessSensor();
if (sensorDetails != null) {
- mScreenOffBrightnessSensor.type = sensorDetails.getType();
- mScreenOffBrightnessSensor.name = sensorDetails.getName();
+ loadSensorData(sensorDetails, mScreenOffBrightnessSensor);
}
}
private void loadProxSensorFromDdc(DisplayConfiguration config) {
SensorDetails sensorDetails = config.getProxSensor();
if (sensorDetails != null) {
- mProximitySensor.name = sensorDetails.getName();
- mProximitySensor.type = sensorDetails.getType();
- final RefreshRateRange rr = sensorDetails.getRefreshRate();
- if (rr != null) {
- mProximitySensor.minRefreshRate = rr.getMinimum().floatValue();
- mProximitySensor.maxRefreshRate = rr.getMaximum().floatValue();
+ String name = sensorDetails.getName();
+ String type = sensorDetails.getType();
+ if ("".equals(name) && "".equals(type)) {
+ // <proxSensor> with empty values to the config means no sensor should be used
+ mProximitySensor = null;
+ } else {
+ mProximitySensor = new SensorData();
+ loadSensorData(sensorDetails, mProximitySensor);
}
} else {
setProxSensorUnspecified();
}
}
+ private void loadSensorData(@NonNull SensorDetails sensorDetails,
+ @NonNull SensorData sensorData) {
+ sensorData.name = sensorDetails.getName();
+ sensorData.type = sensorDetails.getType();
+ final RefreshRateRange rr = sensorDetails.getRefreshRate();
+ if (rr != null) {
+ sensorData.minRefreshRate = rr.getMinimum().floatValue();
+ sensorData.maxRefreshRate = rr.getMaximum().floatValue();
+ }
+ }
+
private void loadBrightnessChangeThresholdsFromXml() {
loadBrightnessChangeThresholds(/* config= */ null);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 1162231..7e8771e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -4230,6 +4230,13 @@
}
@VisibleForTesting
+ void overrideSensorManager(SensorManager sensorManager) {
+ synchronized (mSyncRoot) {
+ mSensorManager = sensorManager;
+ }
+ }
+
+ @VisibleForTesting
final class LocalService extends DisplayManagerInternal {
@Override
@@ -4482,7 +4489,7 @@
}
final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
SensorData sensorData = config.getProximitySensor();
- if (sensorData.matches(sensorName, sensorType)) {
+ if (sensorData != null && sensorData.matches(sensorName, sensorType)) {
return new RefreshRateRange(sensorData.minRefreshRate,
sensorData.maxRefreshRate);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 80114cc..ffecf2b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -512,6 +512,9 @@
// of the lead display that this DPC should follow.
private float mBrightnessToFollow;
+ // Indicates whether we should ramp slowly to the brightness value to follow.
+ private boolean mBrightnessToFollowSlowChange;
+
// The last auto brightness adjustment that was set by the user and not temporary. Set to
// Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
private float mAutoBrightnessAdjustment;
@@ -812,7 +815,8 @@
}
@Override
- public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) {
+ public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
+ boolean slowChange) {
mBrightnessRangeController.onAmbientLuxChange(ambientLux);
if (nits < 0) {
mBrightnessToFollow = leadDisplayBrightness;
@@ -825,6 +829,7 @@
mBrightnessToFollow = leadDisplayBrightness;
}
}
+ mBrightnessToFollowSlowChange = slowChange;
sendUpdatePowerState();
}
@@ -842,7 +847,7 @@
mDisplayBrightnessFollowers.remove(follower.getDisplayId());
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
- /* ambientLux= */ 0), mClock.uptimeMillis());
+ /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
}
@@ -852,7 +857,7 @@
DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i);
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
- /* ambientLux= */ 0), mClock.uptimeMillis());
+ /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
mDisplayBrightnessFollowers.clear();
}
@@ -1559,6 +1564,7 @@
final int oldState = mPowerState.getScreenState();
animateScreenStateChange(state, performScreenOffTransition);
state = mPowerState.getScreenState();
+ boolean slowChange = false;
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
@@ -1567,6 +1573,7 @@
if (Float.isNaN(brightnessState) && isValidBrightnessValue(mBrightnessToFollow)) {
brightnessState = mBrightnessToFollow;
+ slowChange = mBrightnessToFollowSlowChange;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_FOLLOWER);
}
@@ -1583,12 +1590,12 @@
mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
final boolean autoBrightnessEnabled = mUseAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
- && Float.isNaN(brightnessState)
- && mAutomaticBrightnessController != null
- && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_FOLLOWER;
+ && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_OVERRIDE
+ && mAutomaticBrightnessController != null;
final boolean autoBrightnessDisabledDueToDisplayOff = mUseAutoBrightness
&& !(state == Display.STATE_ON || autoBrightnessEnabledInDoze);
final int autoBrightnessState = autoBrightnessEnabled
+ && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_FOLLOWER
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
: autoBrightnessDisabledDueToDisplayOff
? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
@@ -1648,9 +1655,11 @@
mShouldResetShortTermModel);
mShouldResetShortTermModel = false;
}
- mBrightnessRangeController.setAutoBrightnessEnabled(mUseAutoBrightness
+ mBrightnessRangeController.setAutoBrightnessEnabled(autoBrightnessEnabled
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
- : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+ : autoBrightnessDisabledDueToDisplayOff
+ ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
+ : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
if (mBrightnessTracker != null) {
mBrightnessTracker.setShouldCollectColorSample(mBrightnessConfiguration != null
@@ -1661,7 +1670,6 @@
float rawBrightnessState = brightnessState;
// Apply auto-brightness.
- boolean slowChange = false;
if (Float.isNaN(brightnessState)) {
float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
if (autoBrightnessEnabled) {
@@ -1740,6 +1748,14 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
+ float ambientLux = mAutomaticBrightnessController == null ? 0
+ : mAutomaticBrightnessController.getAmbientLux();
+ for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
+ DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
+ follower.setBrightnessToFollow(rawBrightnessState, convertToNits(rawBrightnessState),
+ ambientLux, slowChange);
+ }
+
// Now that a desired brightness has been calculated, apply brightness throttling. The
// dimming and low power transformations that follow can only dim brightness further.
//
@@ -1762,14 +1778,6 @@
mAppliedThrottling = false;
}
- float ambientLux = mAutomaticBrightnessController == null ? 0
- : mAutomaticBrightnessController.getAmbientLux();
- for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
- DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
- follower.setBrightnessToFollow(rawBrightnessState, convertToNits(rawBrightnessState),
- ambientLux);
- }
-
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -2157,8 +2165,9 @@
final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
- displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
+ return mInjector.getHighBrightnessModeController(mHandler, info.width, info.height,
+ displayToken, displayUniqueId, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX, hbmData,
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@Override
public float getHdrBrightnessFromSdr(
@@ -2294,29 +2303,23 @@
}
private void loadAmbientLightSensor() {
- DisplayDeviceConfig.SensorData lightSensor = mDisplayDeviceConfig.getAmbientLightSensor();
final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY
? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK;
- mLightSensor = SensorUtils.findSensor(mSensorManager, lightSensor.type, lightSensor.name,
- fallbackType);
+ mLightSensor = SensorUtils.findSensor(mSensorManager,
+ mDisplayDeviceConfig.getAmbientLightSensor(), fallbackType);
}
private void loadScreenOffBrightnessSensor() {
- DisplayDeviceConfig.SensorData screenOffBrightnessSensor =
- mDisplayDeviceConfig.getScreenOffBrightnessSensor();
mScreenOffBrightnessSensor = SensorUtils.findSensor(mSensorManager,
- screenOffBrightnessSensor.type, screenOffBrightnessSensor.name,
- SensorUtils.NO_FALLBACK);
+ mDisplayDeviceConfig.getScreenOffBrightnessSensor(), SensorUtils.NO_FALLBACK);
}
private void loadProximitySensor() {
if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT || mDisplayId != Display.DEFAULT_DISPLAY) {
return;
}
- final DisplayDeviceConfig.SensorData proxSensor =
- mDisplayDeviceConfig.getProximitySensor();
- mProximitySensor = SensorUtils.findSensor(mSensorManager, proxSensor.type, proxSensor.name,
- Sensor.TYPE_PROXIMITY);
+ mProximitySensor = SensorUtils.findSensor(mSensorManager,
+ mDisplayDeviceConfig.getProximitySensor(), Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
TYPICAL_PROXIMITY_THRESHOLD);
@@ -2949,6 +2952,7 @@
+ mPendingScreenBrightnessSetting);
pw.println(" mTemporaryScreenBrightness=" + mTemporaryScreenBrightness);
pw.println(" mBrightnessToFollow=" + mBrightnessToFollow);
+ pw.println(" mBrightnessToFollowSlowChange=" + mBrightnessToFollowSlowChange);
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mBrightnessReason=" + mBrightnessReason);
pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
@@ -3528,6 +3532,17 @@
brightnessMapper
);
}
+
+ HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
+ int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
+ float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
+ Context context) {
+ return new HighBrightnessModeController(handler, width, height, displayToken,
+ displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg,
+ hbmChangeCallback, hbmMetadata, context);
+ }
}
static class CachedBrightnessInfo {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index c8b0a72..7043af8 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -435,6 +435,9 @@
@Nullable
private BrightnessMappingStrategy mIdleModeBrightnessMapper;
+ // Indicates whether we should ramp slowly to the brightness value to follow.
+ private boolean mBrightnessToFollowSlowChange;
+
private boolean mIsRbcActive;
// Animators.
@@ -1272,6 +1275,7 @@
// actual state instead of the desired one.
animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition());
state = mPowerState.getScreenState();
+ boolean slowChange = false;
final boolean userSetBrightnessChanged = mDisplayBrightnessController
.updateUserSetScreenBrightness();
@@ -1281,13 +1285,18 @@
float rawBrightnessState = displayBrightnessState.getBrightness();
mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason());
+ if (displayBrightnessState.getBrightnessReason().getReason()
+ == BrightnessReason.REASON_FOLLOWER) {
+ slowChange = mBrightnessToFollowSlowChange;
+ }
+
// Take note if the short term model was already active before applying the current
// request changes.
final boolean wasShortTermModelActive =
mAutomaticBrightnessStrategy.isShortTermModelActive();
mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
- brightnessState, mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
+ mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
mDisplayBrightnessController.getLastUserSetScreenBrightness(),
userSetBrightnessChanged);
@@ -1297,15 +1306,16 @@
&& (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()
|| userSetBrightnessChanged);
- mBrightnessRangeController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy
- .shouldUseAutoBrightness()
+ mBrightnessRangeController.setAutoBrightnessEnabled(
+ mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
- : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+ : mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff()
+ ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
+ : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
boolean updateScreenBrightnessSetting = false;
float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness();
// Apply auto-brightness.
- boolean slowChange = false;
int brightnessAdjustmentFlags = 0;
if (Float.isNaN(brightnessState)) {
if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) {
@@ -1322,10 +1332,13 @@
brightnessAdjustmentFlags =
mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags();
updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+ mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
if (mScreenOffBrightnessSensorController != null) {
mScreenOffBrightnessSensorController.setLightSensorEnabled(false);
}
+ } else {
+ mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
}
}
} else {
@@ -1333,6 +1346,7 @@
// to clamping so that they don't go beyond the current max as specified by HBM
// Controller.
brightnessState = clampScreenBrightness(brightnessState);
+ mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
}
// Use default brightness when dozing unless overridden.
@@ -1372,6 +1386,15 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
+ float ambientLux = mAutomaticBrightnessController == null ? 0
+ : mAutomaticBrightnessController.getAmbientLux();
+ for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
+ DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
+ follower.setBrightnessToFollow(rawBrightnessState,
+ mDisplayBrightnessController.convertToNits(rawBrightnessState),
+ ambientLux, slowChange);
+ }
+
// Now that a desired brightness has been calculated, apply brightness throttling. The
// dimming and low power transformations that follow can only dim brightness further.
//
@@ -1394,15 +1417,6 @@
mAppliedThrottling = false;
}
- float ambientLux = mAutomaticBrightnessController == null ? 0
- : mAutomaticBrightnessController.getAmbientLux();
- for (int i = 0; i < displayBrightnessFollowers.size(); i++) {
- DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i);
- follower.setBrightnessToFollow(rawBrightnessState,
- mDisplayBrightnessController.convertToNits(rawBrightnessState),
- ambientLux);
- }
-
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -1804,9 +1818,9 @@
final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
- displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
- (sdrBrightness, maxDesiredHdrSdrRatio) ->
+ return mInjector.getHighBrightnessModeController(mHandler, info.width, info.height,
+ displayToken, displayUniqueId, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX, hbmData, (sdrBrightness, maxDesiredHdrSdrRatio) ->
mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness,
maxDesiredHdrSdrRatio), modeChangeCallback, hbmMetadata, mContext);
}
@@ -1936,19 +1950,15 @@
}
private void loadAmbientLightSensor() {
- DisplayDeviceConfig.SensorData lightSensor = mDisplayDeviceConfig.getAmbientLightSensor();
final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY
? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK;
- mLightSensor = SensorUtils.findSensor(mSensorManager, lightSensor.type, lightSensor.name,
- fallbackType);
+ mLightSensor = SensorUtils.findSensor(mSensorManager,
+ mDisplayDeviceConfig.getAmbientLightSensor(), fallbackType);
}
private void loadScreenOffBrightnessSensor() {
- DisplayDeviceConfig.SensorData screenOffBrightnessSensor =
- mDisplayDeviceConfig.getScreenOffBrightnessSensor();
mScreenOffBrightnessSensor = SensorUtils.findSensor(mSensorManager,
- screenOffBrightnessSensor.type, screenOffBrightnessSensor.name,
- SensorUtils.NO_FALLBACK);
+ mDisplayDeviceConfig.getScreenOffBrightnessSensor(), SensorUtils.NO_FALLBACK);
}
private float clampScreenBrightness(float value) {
@@ -2189,7 +2199,8 @@
}
@Override
- public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) {
+ public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
+ boolean slowChange) {
mBrightnessRangeController.onAmbientLuxChange(ambientLux);
if (nits < 0) {
mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness);
@@ -2202,6 +2213,7 @@
mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness);
}
}
+ mBrightnessToFollowSlowChange = slowChange;
sendUpdatePowerState();
}
@@ -2261,7 +2273,7 @@
mDisplayBrightnessFollowers.remove(follower.getDisplayId());
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
- /* ambientLux= */ 0), mClock.uptimeMillis());
+ /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
}
@@ -2271,7 +2283,7 @@
DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i);
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
- /* ambientLux= */ 0), mClock.uptimeMillis());
+ /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
mDisplayBrightnessFollowers.clear();
}
@@ -2341,6 +2353,7 @@
pw.println(" mReportedToPolicy="
+ reportedToPolicyToString(mReportedScreenStateToPolicy));
pw.println(" mIsRbcActive=" + mIsRbcActive);
+ pw.println(" mBrightnessToFollowSlowChange=" + mBrightnessToFollowSlowChange);
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
mAutomaticBrightnessStrategy.dump(ipw);
@@ -2892,6 +2905,17 @@
brightnessMapper
);
}
+
+ HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
+ int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
+ float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
+ Context context) {
+ return new HighBrightnessModeController(handler, width, height, displayToken,
+ displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg,
+ hbmChangeCallback, hbmMetadata, context);
+ }
}
static class CachedBrightnessInfo {
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index 5fbbcbd..e3108c9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -201,8 +201,10 @@
* @param nits The brightness value in nits if the device supports nits. Set to a negative
* number otherwise.
* @param ambientLux The lux value that will be passed to {@link HighBrightnessModeController}
+ * @param slowChange Indicates whether we should slowly animate to the given brightness value.
*/
- void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux);
+ void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
+ boolean slowChange);
/**
* Add an additional display that will copy the brightness value from this display. This is used
diff --git a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java
index c074786..882c02f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java
@@ -358,10 +358,8 @@
if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT || mDisplayId != Display.DEFAULT_DISPLAY) {
return;
}
- final DisplayDeviceConfig.SensorData proxSensor =
- mDisplayDeviceConfig.getProximitySensor();
- mProximitySensor = SensorUtils.findSensor(mSensorManager, proxSensor.type, proxSensor.name,
- Sensor.TYPE_PROXIMITY);
+ mProximitySensor = SensorUtils.findSensor(mSensorManager,
+ mDisplayDeviceConfig.getProximitySensor(), Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
TYPICAL_PROXIMITY_THRESHOLD);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 0e885dc..bcd5259 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -73,6 +73,9 @@
// the user has enabled the auto-brightness from the settings, it is disabled because the
// display is off
private boolean mIsAutoBrightnessEnabled = false;
+ // Indicates if auto-brightness is disabled due to the display being off. Needed for metric
+ // purposes.
+ private boolean mAutoBrightnessDisabledDueToDisplayOff;
// If the auto-brightness model for the last manual changes done by the user.
private boolean mIsShortTermModelActive = false;
@@ -96,24 +99,21 @@
* AutomaticBrightnessController accounting for any manual changes made by the user.
*/
public void setAutoBrightnessState(int targetDisplayState,
- boolean allowAutoBrightnessWhileDozingConfig,
- float brightnessState, int brightnessReason, int policy,
+ boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
final boolean autoBrightnessEnabledInDoze =
allowAutoBrightnessWhileDozingConfig
&& Display.isDozeState(targetDisplayState);
mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
&& (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
- && (Float.isNaN(brightnessState)
- || brightnessReason == BrightnessReason.REASON_TEMPORARY
- || brightnessReason == BrightnessReason.REASON_BOOST)
- && mAutomaticBrightnessController != null
- && brightnessReason != BrightnessReason.REASON_FOLLOWER;
- final boolean autoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness()
+ && brightnessReason != BrightnessReason.REASON_OVERRIDE
+ && mAutomaticBrightnessController != null;
+ mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness()
&& !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze);
final int autoBrightnessState = mIsAutoBrightnessEnabled
+ && brightnessReason != BrightnessReason.REASON_FOLLOWER
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
- : autoBrightnessDisabledDueToDisplayOff
+ : mAutoBrightnessDisabledDueToDisplayOff
? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
: AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
@@ -125,6 +125,10 @@
return mIsAutoBrightnessEnabled;
}
+ public boolean isAutoBrightnessDisabledDueToDisplayOff() {
+ return mAutoBrightnessDisabledDueToDisplayOff;
+ }
+
/**
* Updates the {@link BrightnessConfiguration} that is currently being used by the associated
* display.
@@ -287,8 +291,6 @@
mAutoBrightnessAdjustmentReasonsFlags = isTemporaryAutoBrightnessAdjustmentApplied()
? BrightnessReason.ADJUSTMENT_AUTO_TEMP
: BrightnessReason.ADJUSTMENT_AUTO;
- mAppliedAutoBrightness = BrightnessUtils.isValidBrightnessValue(brightnessState)
- || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT;
float newAutoBrightnessAdjustment =
(mAutomaticBrightnessController != null)
? mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()
@@ -345,8 +347,7 @@
/**
* Sets if the auto-brightness is applied on the latest brightness change.
*/
- @VisibleForTesting
- void setAutoBrightnessApplied(boolean autoBrightnessApplied) {
+ public void setAutoBrightnessApplied(boolean autoBrightnessApplied) {
mAppliedAutoBrightness = autoBrightnessApplied;
}
diff --git a/services/core/java/com/android/server/display/utils/SensorUtils.java b/services/core/java/com/android/server/display/utils/SensorUtils.java
index 48bc46c..56321cd 100644
--- a/services/core/java/com/android/server/display/utils/SensorUtils.java
+++ b/services/core/java/com/android/server/display/utils/SensorUtils.java
@@ -16,10 +16,13 @@
package com.android.server.display.utils;
+import android.annotation.Nullable;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.text.TextUtils;
+import com.android.server.display.DisplayDeviceConfig;
+
import java.util.List;
/**
@@ -29,17 +32,26 @@
public static final int NO_FALLBACK = 0;
/**
+ * Finds the specified sensor for SensorData from DisplayDeviceConfig.
+ */
+ @Nullable
+ public static Sensor findSensor(@Nullable SensorManager sensorManager,
+ @Nullable DisplayDeviceConfig.SensorData sensorData, int fallbackType) {
+ if (sensorData == null) {
+ return null;
+ } else {
+ return findSensor(sensorManager, sensorData.type, sensorData.name, fallbackType);
+ }
+ }
+ /**
* Finds the specified sensor by type and name using SensorManager.
*/
- public static Sensor findSensor(SensorManager sensorManager, String sensorType,
- String sensorName, int fallbackType) {
+ @Nullable
+ public static Sensor findSensor(@Nullable SensorManager sensorManager,
+ @Nullable String sensorType, @Nullable String sensorName, int fallbackType) {
if (sensorManager == null) {
return null;
}
-
- if ("".equals(sensorName) && "".equals(sensorType)) {
- return null;
- }
final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
if (isNameSpecified || isTypeSpecified) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 41651fd..68cf59f 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -203,9 +203,7 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- synchronized (mLock) {
- updateWhenToDreamSettings();
- }
+ updateWhenToDreamSettings();
}
}
@@ -257,15 +255,7 @@
if (Build.IS_DEBUGGABLE) {
SystemProperties.addChangeCallback(mSystemPropertiesChanged);
}
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- writePulseGestureEnabled();
- synchronized (mLock) {
- stopDreamLocked(false /*immediate*/, "user switched");
- }
- }
- }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE), false,
mDozeEnabledObserver, UserHandle.USER_ALL);
@@ -303,6 +293,18 @@
}
}
+ @Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ updateWhenToDreamSettings();
+
+ mHandler.post(() -> {
+ writePulseGestureEnabled();
+ synchronized (mLock) {
+ stopDreamLocked(false /*immediate*/, "user switched");
+ }
+ });
+ }
+
private void dumpInternal(PrintWriter pw) {
synchronized (mLock) {
pw.println("DREAM MANAGER (dumpsys dreams)");
@@ -318,6 +320,7 @@
pw.println("mWhenToDream=" + mWhenToDream);
pw.println("mKeepDreamingWhenUnpluggingDefault=" + mKeepDreamingWhenUnpluggingDefault);
pw.println("getDozeComponent()=" + getDozeComponent());
+ pw.println("mDreamOverlayServiceName=" + mDreamOverlayServiceName.flattenToString());
pw.println();
DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> mController.dump(pw1), pw, "", 200);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 090d728..77213bf 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -601,6 +601,7 @@
})
@interface RcProfileSource {}
+ static final int HDMI_EARC_STATUS_UNKNOWN = -1;
static final int HDMI_EARC_STATUS_IDLE = IEArcStatus.IDLE; // IDLE1
static final int HDMI_EARC_STATUS_EARC_PENDING =
IEArcStatus.EARC_PENDING; // DISC1 and DISC2
@@ -609,6 +610,7 @@
IEArcStatus.EARC_CONNECTED; // eARC connected
@IntDef({
+ HDMI_EARC_STATUS_UNKNOWN,
HDMI_EARC_STATUS_IDLE,
HDMI_EARC_STATUS_EARC_PENDING,
HDMI_EARC_STATUS_ARC_PENDING,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
index 9437c4f..7ae7d5c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
@@ -16,6 +16,11 @@
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_IDLE;
+
import android.stats.hdmi.HdmiStatsEnums;
import com.android.internal.annotations.VisibleForTesting;
@@ -193,6 +198,46 @@
}
/**
+ * Writes a HdmiEarcStatusReported atom representing a eARC status change.
+ * @param isSupported Whether the hardware supports eARC.
+ * @param isEnabled Whether eARC is enabled.
+ * @param oldConnectionState If enumLogReason == HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED,
+ * the state just before the change. Otherwise, the current state.
+ * @param newConnectionState If enumLogReason == HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED,
+ * the state just after the change. Otherwise, the current state.
+ * @param enumLogReason The event that triggered the log.
+ */
+ public void earcStatusChanged(boolean isSupported, boolean isEnabled, int oldConnectionState,
+ int newConnectionState, int enumLogReason) {
+ int enumOldConnectionState = earcStateToEnum(oldConnectionState);
+ int enumNewConnectionState = earcStateToEnum(newConnectionState);
+
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.HDMI_EARC_STATUS_REPORTED,
+ isSupported,
+ isEnabled,
+ enumOldConnectionState,
+ enumNewConnectionState,
+ enumLogReason
+ );
+ }
+
+ private int earcStateToEnum(int earcState) {
+ switch (earcState) {
+ case HDMI_EARC_STATUS_IDLE:
+ return HdmiStatsEnums.HDMI_EARC_STATUS_IDLE;
+ case HDMI_EARC_STATUS_EARC_PENDING:
+ return HdmiStatsEnums.HDMI_EARC_STATUS_EARC_PENDING;
+ case HDMI_EARC_STATUS_ARC_PENDING:
+ return HdmiStatsEnums.HDMI_EARC_STATUS_ARC_PENDING;
+ case HDMI_EARC_STATUS_EARC_CONNECTED:
+ return HdmiStatsEnums.HDMI_EARC_STATUS_EARC_CONNECTED;
+ default:
+ return HdmiStatsEnums.HDMI_EARC_STATUS_UNKNOWN;
+ }
+ }
+
+ /**
* Contains the required arguments for creating any HdmiCecMessageReported atom
*/
private class MessageReportedGenericArgs {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 698ee0b..29ed9da 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -213,7 +213,13 @@
}
private int toAndroidKeycodeIfMatched(byte[] cecKeycodeAndParams) {
- if (Arrays.equals(mCecKeycodeAndParams, cecKeycodeAndParams)) {
+ if (cecKeycodeAndParams.length < mCecKeycodeAndParams.length) {
+ return UNSUPPORTED_KEYCODE;
+ }
+ byte[] trimmedCecKeycodeAndParams = new byte[mCecKeycodeAndParams.length];
+ System.arraycopy(cecKeycodeAndParams, 0, trimmedCecKeycodeAndParams, 0,
+ mCecKeycodeAndParams.length);
+ if (Arrays.equals(mCecKeycodeAndParams, trimmedCecKeycodeAndParams)) {
return mAndroidKeycode;
} else {
return UNSUPPORTED_KEYCODE;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 3ec3f94..c73a07d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -110,7 +110,8 @@
new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error != SendMessageResult.SUCCESS) {
+ // In consideration of occasional transmission failures.
+ if (error == SendMessageResult.NACK) {
HdmiLogger.debug(
"AVR did not respond to <Give System Audio Mode Status>");
mService.setSystemAudioActivated(false);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 5ef06f9..7087062 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1184,7 +1184,11 @@
if (mService.isSystemAudioActivated()) {
return Constants.ABORT_NOT_IN_CORRECT_MODE;
} else {
- mService.setStreamMusicVolume(message.getAudioVolumeLevel(), 0);
+ int audioVolumeLevel = message.getAudioVolumeLevel();
+ if (audioVolumeLevel >= AudioStatus.MIN_VOLUME
+ && audioVolumeLevel <= AudioStatus.MAX_VOLUME) {
+ mService.setStreamMusicVolume(audioVolumeLevel, 0);
+ }
return Constants.HANDLED;
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index adcff4c..e9959c2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -287,6 +287,17 @@
}
/**
+ * Build <Image View On> command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildImageViewOn(int src, int dest) {
+ return HdmiCecMessage.build(src, dest, Constants.MESSAGE_IMAGE_VIEW_ON);
+ }
+
+ /**
* Build <Request Active Source> command.
*
* @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3eab4b0..3e3835b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -28,6 +28,7 @@
import static com.android.server.hdmi.Constants.DISABLED;
import static com.android.server.hdmi.Constants.ENABLED;
import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_UNKNOWN;
import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
@@ -91,6 +92,7 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
+import android.stats.hdmi.HdmiStatsEnums;
import android.sysprop.HdmiProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -1529,7 +1531,32 @@
@ServiceThreadOnly
void sendCecCommand(HdmiCecMessage command) {
assertRunOnServiceThread();
- sendCecCommand(command, null);
+ switch (command.getOpcode()) {
+ case Constants.MESSAGE_ACTIVE_SOURCE:
+ case Constants.MESSAGE_IMAGE_VIEW_ON:
+ case Constants.MESSAGE_INACTIVE_SOURCE:
+ case Constants.MESSAGE_ROUTING_CHANGE:
+ case Constants.MESSAGE_SET_STREAM_PATH:
+ case Constants.MESSAGE_TEXT_VIEW_ON:
+ sendCecCommandWithRetries(command);
+ break;
+ default:
+ sendCecCommand(command, null);
+ }
+ }
+
+ /**
+ * Create a {@link SendCecCommandAction} that will retry to send the CEC message in case it
+ * fails.
+ * @param command that has to be sent in the CEC bus.
+ */
+ @ServiceThreadOnly
+ public void sendCecCommandWithRetries(HdmiCecMessage command) {
+ assertRunOnServiceThread();
+ HdmiCecLocalDevice localDevice = getAllCecLocalDevices().get(0);
+ if (localDevice != null) {
+ localDevice.addAndStartAction(new SendCecCommandAction(localDevice, command));
+ }
}
/**
@@ -3530,7 +3557,8 @@
}
}
- private boolean isEarcSupported() {
+ @VisibleForTesting
+ protected boolean isEarcSupported() {
synchronized (mLock) {
return mEarcSupported;
}
@@ -3648,6 +3676,11 @@
setEarcEnabledInHal(false, false);
}
}
+ if (isTvDevice()) {
+ int earcStatus = getEarcStatus();
+ getAtomWriter().earcStatusChanged(isEarcSupported(), isEarcEnabled(),
+ earcStatus, earcStatus, HdmiStatsEnums.LOG_REASON_WAKE);
+ }
// TODO: Initialize MHL local devices.
}
@@ -4678,6 +4711,17 @@
}
@ServiceThreadOnly
+ private int getEarcStatus() {
+ assertRunOnServiceThread();
+ if (mEarcLocalDevice != null) {
+ synchronized (mLock) {
+ return mEarcLocalDevice.mEarcStatus;
+ }
+ }
+ return HDMI_EARC_STATUS_UNKNOWN;
+ }
+
+ @ServiceThreadOnly
@VisibleForTesting
HdmiEarcLocalDevice getEarcLocalDevice() {
assertRunOnServiceThread();
@@ -4729,13 +4773,19 @@
Slog.w(TAG, "Tried to update eARC status on a port that doesn't support eARC.");
return;
}
+ int oldEarcStatus = getEarcStatus();
if (mEarcLocalDevice != null) {
mEarcLocalDevice.handleEarcStateChange(status);
+ getAtomWriter().earcStatusChanged(isEarcSupported(), isEarcEnabled(),
+ oldEarcStatus, status, HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED);
} else if (status == HDMI_EARC_STATUS_ARC_PENDING) {
// If eARC is disabled, the local device is null. This is why we notify
// AudioService here that the eARC connection is terminated.
+ HdmiLogger.debug("eARC state change [new: HDMI_EARC_STATUS_ARC_PENDING(2)]");
notifyEarcStatusToAudioService(false, new ArrayList<>());
startArcAction(true, null);
+ getAtomWriter().earcStatusChanged(isEarcSupported(), isEarcEnabled(),
+ oldEarcStatus, status, HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED);
}
}
diff --git a/services/core/java/com/android/server/hdmi/SendCecCommandAction.java b/services/core/java/com/android/server/hdmi/SendCecCommandAction.java
new file mode 100644
index 0000000..000ada8
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SendCecCommandAction.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hdmi;
+
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Action that sends a CEC command. If the message fails to be sent, it tries again for
+ * RETRANSMISSION_COUNT times.
+ */
+public class SendCecCommandAction extends HdmiCecFeatureAction {
+ private static final String TAG = "SendCecCommandAction";
+ private static final int RETRANSMISSION_COUNT = 2;
+ private static final int STATE_WAIT_FOR_RESEND_COMMAND = 1;
+ static final int SEND_COMMAND_RETRY_MS = 300;
+
+ private final HdmiCecMessage mCommand;
+ private int mRetransmissionCount = 0;
+ private final SendMessageCallback mCallback = new SendMessageCallback(){
+ @Override
+ public void onSendCompleted(int result) {
+ if (result != SendMessageResult.SUCCESS
+ && mRetransmissionCount++ < RETRANSMISSION_COUNT) {
+ mState = STATE_WAIT_FOR_RESEND_COMMAND;
+ addTimer(mState, SEND_COMMAND_RETRY_MS);
+ } else {
+ finish();
+ }
+ }
+ };
+
+ SendCecCommandAction(HdmiCecLocalDevice source, HdmiCecMessage command) {
+ super(source);
+ mCommand = command;
+ }
+
+ @Override
+ boolean start() {
+ Slog.d(TAG, "SendCecCommandAction started");
+ sendCommand(mCommand, mCallback);
+ return true;
+ }
+
+ @Override
+ void handleTimerEvent(int state) {
+ if (mState != state) {
+ Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state
+ + "]");
+ return;
+ }
+ if (mState == STATE_WAIT_FOR_RESEND_COMMAND) {
+ Slog.d(TAG, "sendCecCommand failed, retry");
+ sendCommand(mCommand, mCallback);
+ }
+ }
+
+ @Override
+ boolean processCommand(HdmiCecMessage command) {
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index c3073da..52eede7 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -337,6 +337,10 @@
// Ask IMMS to make ink window ready.
mInkWindowInitRunnable.run();
mInkWindowInitRunnable = null;
+ return;
+ } else if (event.isHoverEvent()) {
+ // Hover events need not be recorded to buffer.
+ return;
}
// If handwriting delegation is ongoing, don't clear the buffer so that multiple strokes
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index ba9e280..b0b1d67 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -352,6 +352,7 @@
clearCurMethodAndSessions();
mService.clearInputShownLocked();
mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
+ mService.resetSystemUiLocked();
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 57f8d14..4dbd820 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -633,8 +633,9 @@
private InputMethodSubtype mCurrentSubtype;
/**
- * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}
+ * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}.
*/
+ @GuardedBy("ImfLock.class")
private boolean mCurPerceptible;
/**
@@ -748,33 +749,26 @@
SparseArray<AccessibilitySessionState> mEnabledAccessibilitySessions = new SparseArray<>();
/**
- * True if the device is currently interactive with user. The value is true initially.
+ * {@code true} if the device is currently interactive with the user, initially true.
+ *
+ * @see #handleSetInteractive
*/
+ @GuardedBy("ImfLock.class")
boolean mIsInteractive = true;
+ @GuardedBy("ImfLock.class")
+ @InputMethodService.BackDispositionMode
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
- * A set of status bits regarding the active IME.
+ * The {@link InputMethodService.ImeWindowVisibility} of the currently bound IME,
+ * or {@code 0} if no IME is bound.
*
- * <p>This value is a combination of following two bits:</p>
- * <dl>
- * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
- * <dd>
- * If this bit is ON, connected IME is ready to accept touch/key events.
- * </dd>
- * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
- * <dd>
- * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
- * </dd>
- * <dt>{@link InputMethodService#IME_INVISIBLE}</dt>
- * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
- * currently invisible.
- * </dd>
- * </dl>
- * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
+ * <p><em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
* {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
*/
+ @GuardedBy("ImfLock.class")
+ @InputMethodService.ImeWindowVisibility
int mImeWindowVis;
private LocaleList mLastSystemLocales;
@@ -1535,7 +1529,6 @@
// Uh oh, current input method is no longer around!
// Pick another one...
Slog.i(TAG, "Current input method removed: " + curInputMethodId);
- updateSystemUiLocked(0 /* vis */, mBackDisposition);
if (!chooseNewDefaultIMELocked()) {
changed = true;
curIm = null;
@@ -2938,7 +2931,6 @@
sessionState.mSession.finishSession();
} catch (RemoteException e) {
Slog.w(TAG, "Session failed to close due to remote exception", e);
- updateSystemUiLocked(0 /* vis */, mBackDisposition);
}
sessionState.mSession = null;
}
@@ -3048,15 +3040,20 @@
}
@GuardedBy("ImfLock.class")
- private boolean shouldShowImeSwitcherLocked(int visibility) {
+ private boolean shouldShowImeSwitcherLocked(
+ @InputMethodService.ImeWindowVisibility int visibility) {
if (!mShowOngoingImeSwitcherForPhones) return false;
+ // When the IME switcher dialog is shown, the IME switcher button should be hidden.
if (mMenuController.getSwitchingDialogLocked() != null) return false;
+ // When we are switching IMEs, the IME switcher button should be hidden.
+ if (!Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+ return false;
+ }
if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
&& mWindowManagerInternal.isKeyguardSecure(mSettings.getCurrentUserId())) {
return false;
}
- if ((visibility & InputMethodService.IME_ACTIVE) == 0
- || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
+ if ((visibility & InputMethodService.IME_ACTIVE) == 0) {
return false;
}
if (mWindowManagerInternal.isHardKeyboardAvailable()) {
@@ -3115,7 +3112,9 @@
@BinderThread
@SuppressWarnings("deprecation")
- private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
+ private void setImeWindowStatus(@NonNull IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
synchronized (ImfLock.class) {
@@ -3132,7 +3131,7 @@
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- updateSystemUiLocked(vis, backDisposition);
+ updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
final boolean dismissImeOnBackKeyPressed;
@@ -3167,37 +3166,46 @@
private void updateImeWindowStatus(boolean disableImeIcon) {
synchronized (ImfLock.class) {
- if (disableImeIcon) {
- updateSystemUiLocked(0, mBackDisposition);
- } else {
- updateSystemUiLocked();
- }
+ // TODO(b/285109020): disableImeIcon should be stored in a property like
+ // mIsSwitcherIconDisabled, but it is currently not reliably cleared.
+ updateSystemUiLocked(disableImeIcon ? 0 : mImeWindowVis, mBackDisposition);
}
}
@GuardedBy("ImfLock.class")
void updateSystemUiLocked() {
+ // This is only used by InputMethodMenuController to trigger the IME switcher icon
+ // visibility, by having {@code shouldShowImeSwitcherLocked} called, which depends on the
+ // visibility of the IME switcher dialog.
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
// Caution! This method is called in this class. Handle multi-user carefully
@GuardedBy("ImfLock.class")
- private void updateSystemUiLocked(int vis, int backDisposition) {
+ private void updateSystemUiLocked(@InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition) {
if (getCurTokenLocked() == null) {
return;
}
if (DEBUG) {
Slog.d(TAG, "IME window vis: " + vis
- + " active: " + (vis & InputMethodService.IME_ACTIVE)
- + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
+ + " active: " + ((vis & InputMethodService.IME_ACTIVE) != 0)
+ + " visible: " + ((vis & InputMethodService.IME_VISIBLE) != 0)
+ + " backDisposition: " + backDisposition
+ + " isInteractive: " + mIsInteractive
+ + " curPerceptible: " + mCurPerceptible
+ " displayId: " + mCurTokenDisplayId);
}
// TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
- // all updateSystemUi happens on system privilege.
+ // all updateSystemUi happens on system privilege.
final long ident = Binder.clearCallingIdentity();
try {
- if (!mCurPerceptible) {
+ if (!mIsInteractive) {
+ // When we are not interactive,
+ // the visibility should be 0 (no IME icons should be shown).
+ vis = 0;
+ } else if (!mCurPerceptible) {
if ((vis & InputMethodService.IME_VISIBLE) != 0) {
vis &= ~InputMethodService.IME_VISIBLE;
vis |= InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
@@ -3205,7 +3213,12 @@
} else {
vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
}
- // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
+ if (mMenuController.getSwitchingDialogLocked() != null
+ || !Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+ // When the IME switcher dialog is shown, or we are switching IMEs,
+ // the back button should be in the default state (as if the IME is not shown).
+ backDisposition = InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING;
+ }
final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
if (mStatusBarManagerInternal != null) {
mStatusBarManagerInternal.setImeWindowStatus(mCurTokenDisplayId,
@@ -3527,7 +3540,7 @@
return;
}
mCurPerceptible = perceptible;
- updateSystemUiLocked();
+ updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
});
}
@@ -5089,8 +5102,11 @@
private void handleSetInteractive(final boolean interactive) {
synchronized (ImfLock.class) {
+ if (mIsInteractive == interactive) {
+ return;
+ }
mIsInteractive = interactive;
- updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
+ updateSystemUiLocked(mImeWindowVis, mBackDisposition);
// Inform the current client of the change in active status
if (mCurClient == null || mCurClient.mClient == null) {
@@ -5769,7 +5785,7 @@
// input target changed, in case seeing the dialog dismiss flickering during
// the next focused window starting the input connection.
if (mLastImeTargetWindow != mCurFocusedWindow) {
- mMenuController.hideInputMethodMenu();
+ mMenuController.hideInputMethodMenuLocked();
}
}
}
@@ -6725,7 +6741,8 @@
@BinderThread
@Override
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition) {
mImms.setImeWindowStatus(mToken, vis, backDisposition);
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index c212e8e..c2ef83d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -175,13 +175,13 @@
int subtypeId = mSubtypeIds[which];
adapter.mCheckedItem = which;
adapter.notifyDataSetChanged();
- hideInputMethodMenu();
if (im != null) {
if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
subtypeId = NOT_A_SUBTYPE_ID;
}
mService.setInputMethodLocked(im.getId(), subtypeId);
}
+ hideInputMethodMenuLocked();
}
};
mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
@@ -220,12 +220,18 @@
}
}
+ /**
+ * Hides the input method switcher menu.
+ */
void hideInputMethodMenu() {
synchronized (ImfLock.class) {
hideInputMethodMenuLocked();
}
}
+ /**
+ * Hides the input method switcher menu, synchronised version of {@link #hideInputMethodMenu}.
+ */
@GuardedBy("ImfLock.class")
void hideInputMethodMenuLocked() {
if (DEBUG) Slog.v(TAG, "Hide switching menu");
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 89dad26..6124b55 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -468,9 +468,10 @@
}
for (int i = mLightsById.size() - 1; i >= 0; i--) {
- final int type = mLightsById.keyAt(i);
+ LightImpl light = mLightsById.valueAt(i);
+ final int type = light.mHwLight.type;
if (0 <= type && type < mLightsByType.length) {
- mLightsByType[type] = mLightsById.valueAt(i);
+ mLightsByType[type] = light;
}
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index c0cce6f..78c8cde 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -458,12 +458,12 @@
// capabilities.
capabilities = networkAttributes.mCapabilities;
Log.i(TAG, String.format(
- "updateNetworkState, state=%s, connected=%s, network=%s, capabilities=%s"
+ "updateNetworkState, state=%s, connected=%s, network=%s, capabilityFlags=%d"
+ ", availableNetworkCount: %d",
agpsDataConnStateAsString(),
isConnected,
network,
- capabilities,
+ NetworkAttributes.getCapabilityFlags(capabilities),
mAvailableNetworkAttributes.size()));
if (native_is_agps_ril_supported()) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 7009a41..ce3fb85 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -166,6 +166,7 @@
* @param userId The ID of the user to whose lock screen the platform key must be bound.
* @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
* @throws KeyStoreException if there is an error in AndroidKeyStore.
+ * @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
* @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
@@ -174,7 +175,7 @@
@VisibleForTesting
void regenerate(int userId)
throws NoSuchAlgorithmException, KeyStoreException, IOException,
- RemoteException {
+ RemoteException, InsecureUserException {
int generationId = getGenerationId(userId);
int nextId;
if (generationId == -1) {
@@ -195,13 +196,14 @@
* @throws UnrecoverableKeyException if the key could not be recovered.
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws IOException if there was an issue with local database update.
+ * @throws InsecureUserException if the user does not have a lock screen set.
* @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
public PlatformEncryptionKey getEncryptKey(int userId)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
- IOException, RemoteException {
+ IOException, RemoteException, InsecureUserException {
init(userId);
try {
// Try to see if the decryption key is still accessible before using the encryption key.
@@ -254,7 +256,7 @@
*/
public PlatformDecryptionKey getDecryptKey(int userId)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
- IOException, RemoteException {
+ IOException, InsecureUserException, RemoteException {
init(userId);
try {
PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId);
@@ -328,7 +330,7 @@
*/
void init(int userId)
throws KeyStoreException, NoSuchAlgorithmException, IOException,
- RemoteException {
+ RemoteException, InsecureUserException {
int generationId = getGenerationId(userId);
if (isKeyLoaded(userId, generationId)) {
Log.i(TAG, String.format(
@@ -414,7 +416,8 @@
* @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*/
private void generateAndLoadKey(int userId, int generationId)
- throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException {
+ throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException,
+ InsecureUserException {
String encryptAlias = getEncryptAlias(userId, generationId);
String decryptAlias = getDecryptAlias(userId, generationId);
// SecretKey implementation doesn't provide reliable way to destroy the secret
@@ -427,23 +430,31 @@
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
// Skip UserAuthenticationRequired for main user
if (userId == UserHandle.USER_SYSTEM) {
+ // attempt to store key will fail if screenlock is not set.
decryptionKeyProtection.setUnlockedDeviceRequired(true);
} else {
// Don't set protection params to prevent losing key.
}
// Store decryption key first since it is more likely to fail.
- mKeyStore.setEntry(
- decryptAlias,
- new KeyStore.SecretKeyEntry(secretKey),
- decryptionKeyProtection.build());
- mKeyStore.setEntry(
- encryptAlias,
- new KeyStore.SecretKeyEntry(secretKey),
- new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .build());
-
+ try {
+ mKeyStore.setEntry(
+ decryptAlias,
+ new KeyStore.SecretKeyEntry(secretKey),
+ decryptionKeyProtection.build());
+ mKeyStore.setEntry(
+ encryptAlias,
+ new KeyStore.SecretKeyEntry(secretKey),
+ new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ } catch (KeyStoreException e) {
+ if (!isDeviceSecure(userId)) {
+ throw new InsecureUserException("Screenlock is not set");
+ } else {
+ throw e;
+ }
+ }
setGenerationId(userId, generationId);
}
@@ -477,4 +488,8 @@
return keyStore;
}
+ private boolean isDeviceSecure(int userId) {
+ return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId);
+ }
+
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 24dbce4..0cfdaf2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -19,6 +19,7 @@
import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
import static android.security.keystore.recovery.RecoveryController.ERROR_DOWNGRADE_CERTIFICATE;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
@@ -750,6 +751,8 @@
throw new RuntimeException(e);
} catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ } catch (InsecureUserException e) {
+ throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
}
try {
@@ -817,6 +820,8 @@
throw new RuntimeException(e);
} catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ } catch (InsecureUserException e) {
+ throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
}
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 47f6485..9185a00 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
import static android.media.VolumeProvider.VOLUME_CONTROL_FIXED;
import static android.media.VolumeProvider.VOLUME_CONTROL_RELATIVE;
@@ -44,7 +45,9 @@
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.MediaMetadata;
+import android.media.MediaRouter2Manager;
import android.media.Rating;
+import android.media.RoutingSessionInfo;
import android.media.VolumeProvider;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
@@ -510,7 +513,33 @@
@Override
public boolean canHandleVolumeKey() {
- return mVolumeControlType != VOLUME_CONTROL_FIXED;
+ if (isPlaybackTypeLocal()) {
+ return true;
+ }
+ if (mVolumeControlType == VOLUME_CONTROL_FIXED) {
+ return false;
+ }
+ if (mVolumeAdjustmentForRemoteGroupSessions) {
+ return true;
+ }
+ // See b/228021646 for details.
+ MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
+ List<RoutingSessionInfo> sessions = mRouter2Manager.getRoutingSessions(mPackageName);
+ boolean foundNonSystemSession = false;
+ boolean remoteSessionAllowVolumeAdjustment = true;
+ for (RoutingSessionInfo session : sessions) {
+ if (!session.isSystemSession()) {
+ foundNonSystemSession = true;
+ if (session.getVolumeHandling() == PLAYBACK_VOLUME_FIXED) {
+ remoteSessionAllowVolumeAdjustment = false;
+ }
+ }
+ }
+ if (!foundNonSystemSession) {
+ Log.d(TAG, "Package " + mPackageName
+ + " has a remote media session but no associated routing session");
+ }
+ return foundNonSystemSession && remoteSessionAllowVolumeAdjustment;
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 26e8fe6..321b74c 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -40,8 +40,6 @@
private static final boolean DEBUG = MediaSessionService.DEBUG;
private static final String TAG = "MediaSessionStack";
- private static final int DUMP_EVENTS_MAX_COUNT = 70;
-
/**
* Listen the change in the media button session.
*/
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index ae6e83a..fc506b6 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -1048,7 +1048,7 @@
// Tear down projection here; necessary to ensure (among other reasons) that
// stop is dispatched to client and cast icon disappears from status bar.
mProjectionGrant.stop();
- throw new IllegalStateException("Don't re-use the resultData to retrieve "
+ throw new SecurityException("Don't re-use the resultData to retrieve "
+ "the same projection instance, and don't use a token that has "
+ "timed out. Don't take multiple captures by invoking "
+ "MediaProjection#createVirtualDisplay multiple times on the "
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 468fa6f..f571c9d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8712,13 +8712,7 @@
ToastRecord lastToast = mToastQueue.remove(index);
- mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
- lastToast.displayId);
- // We passed 'false' for 'removeWindows' so that the client has time to stop
- // rendering (as hide above is a one-way message), otherwise we could crash
- // a client which was actively using a surface made from the token. However
- // we need to schedule a timeout to make sure the token is eventually killed
- // one way or another.
+ // We need to schedule a timeout to make sure the token is eventually killed
scheduleKillTokenTimeout(lastToast);
keepProcessAliveForToastIfNeededLocked(record.pid);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 0605345..3ba307b 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -22,6 +22,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -64,6 +65,8 @@
private static final int LOCAL_LOG_SIZE = 20;
private static final String TAG = "BugreportManagerService";
private static final boolean DEBUG = false;
+ private static final String ROLE_SYSTEM_AUTOMOTIVE_PROJECTION =
+ "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";
private static final String BUGREPORT_SERVICE = "bugreportd";
private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
@@ -326,11 +329,22 @@
// To gain access through the DUMP permission, the OEM has to allow this package explicitly
// via sysconfig and privileged permissions.
- if (mBugreportAllowlistedPackages.contains(callingPackage)
- && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- == PackageManager.PERMISSION_GRANTED) {
+ boolean allowlisted = mBugreportAllowlistedPackages.contains(callingPackage);
+ if (!allowlisted) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ allowlisted = mContext.getSystemService(RoleManager.class).getRoleHolders(
+ ROLE_SYSTEM_AUTOMOTIVE_PROJECTION).contains(callingPackage);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ if (allowlisted && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP) == PackageManager.PERMISSION_GRANTED) {
return;
}
+
// For carrier privileges, this can include user-installed apps. This is essentially a
// function of the current active SIM(s) in the device to let carrier apps through.
final long token = Binder.clearCallingIdentity();
@@ -346,7 +360,8 @@
String message =
callingPackage
- + " does not hold the DUMP permission or is not bugreport-whitelisted "
+ + " does not hold the DUMP permission or is not bugreport-whitelisted or "
+ + "does not have an allowed role "
+ (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+ "to request a bugreport";
Slog.w(TAG, message);
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 12f6a18..5b32a94 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -197,6 +197,7 @@
protected volatile boolean mCacheReady = false;
protected volatile boolean mCacheEnabled = true;
+ protected volatile boolean mNeedToUpdateCacheForImplicitAccess = false;
protected static final boolean CACHE_VALID = true;
protected static final boolean CACHE_INVALID = false;
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index ba5907c..a5fa81d 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -465,6 +465,9 @@
changed = retainOnUpdate
? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
: mImplicitlyQueryable.add(recipientUid, visibleUid);
+ if (!mCacheReady && changed) {
+ mNeedToUpdateCacheForImplicitAccess = true;
+ }
}
if (changed && DEBUG_LOGGING) {
Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
@@ -476,8 +479,6 @@
// Update the cache in a one-off manner since we've got all the information we need.
mShouldFilterCache.put(recipientUid, visibleUid, false);
}
- } else if (changed) {
- invalidateCache("grantImplicitAccess: " + recipientUid + " -> " + visibleUid);
}
if (changed) {
onChanged();
@@ -833,7 +834,12 @@
}
updateEntireShouldFilterCacheInner(snapshot, settings, usersRef[0], USER_ALL);
- onChanged();
+ synchronized (mImplicitlyQueryableLock) {
+ if (mNeedToUpdateCacheForImplicitAccess) {
+ updateShouldFilterCacheForImplicitAccess();
+ mNeedToUpdateCacheForImplicitAccess = false;
+ }
+ }
logCacheRebuilt(reason, SystemClock.currentTimeMicro() - currentTimeUs,
users.length, settings.size());
@@ -845,6 +851,7 @@
}
mCacheReady = true;
+ onChanged();
}, delayMs);
}
@@ -875,6 +882,25 @@
snapshot.getPackageStates().size());
}
+ @GuardedBy("mImplicitlyQueryableLock")
+ private void updateShouldFilterCacheForImplicitAccess() {
+ updateShouldFilterCacheForImplicitAccess(mRetainedImplicitlyQueryable);
+ updateShouldFilterCacheForImplicitAccess(mImplicitlyQueryable);
+ }
+
+ private void updateShouldFilterCacheForImplicitAccess(
+ WatchedSparseSetArray<Integer> queriesMap) {
+ synchronized (mCacheLock) {
+ for (int i = 0; i < queriesMap.size(); i++) {
+ Integer callingUid = queriesMap.keyAt(i);
+ ArraySet<Integer> targetUids = queriesMap.get(callingUid);
+ for (Integer targetUid : targetUids) {
+ mShouldFilterCache.put(callingUid, targetUid, false);
+ }
+ }
+ }
+ }
+
private void updateShouldFilterCacheForPackage(Computer snapshot,
String packageName) {
if (!mCacheReady) {
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 9d70f4c..7aa5c65 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4297,7 +4297,12 @@
if (Process.isIsolatedUid(uid)
&& mPermissionManager.getHotwordDetectionServiceProvider() != null
&& uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
- uid = getIsolatedOwner(uid);
+ try {
+ uid = getIsolatedOwner(uid);
+ } catch (IllegalStateException e) {
+ // If the owner uid doesn't exist, just use the current uid
+ Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+ }
}
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
@@ -4338,7 +4343,12 @@
if (Process.isIsolatedUid(uid)
&& mPermissionManager.getHotwordDetectionServiceProvider() != null
&& uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
- uid = getIsolatedOwner(uid);
+ try {
+ uid = getIsolatedOwner(uid);
+ } catch (IllegalStateException e) {
+ // If the owner uid doesn't exist, just use the current uid
+ Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+ }
}
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 2e85c97..9f3ee1c 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -134,10 +134,6 @@
final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.USER_ALL : userId;
- if (mPm.isPackageDeviceAdmin(packageName, removeUser)) {
- Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
- return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
- }
final PackageSetting uninstalledPs;
final PackageSetting disabledSystemPs;
@@ -699,18 +695,6 @@
final String packageName = versionedPackage.getPackageName();
final long versionCode = versionedPackage.getLongVersionCode();
- if (mPm.mProtectedPackages.isPackageDataProtected(userId, packageName)) {
- mPm.mHandler.post(() -> {
- try {
- Slog.w(TAG, "Attempted to delete protected package: " + packageName);
- observer.onPackageDeleted(packageName,
- PackageManager.DELETE_FAILED_INTERNAL_ERROR, null);
- } catch (RemoteException re) {
- }
- });
- return;
- }
-
try {
if (mPm.mInjector.getLocalService(ActivityTaskManagerInternal.class)
.isBaseOfLockedTask(packageName)) {
@@ -751,6 +735,41 @@
"deletePackage for user " + userId);
}
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // If a package is device admin, or is data protected for any user, it should not be
+ // uninstalled from that user, or from any users if DELETE_ALL_USERS flag is passed.
+ for (int user : users) {
+ if (mPm.isPackageDeviceAdmin(packageName, user)) {
+ mPm.mHandler.post(() -> {
+ try {
+ Slog.w(TAG, "Not removing package " + packageName
+ + ": has active device admin");
+ observer.onPackageDeleted(packageName,
+ PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER, null);
+ } catch (RemoteException e) {
+ // no-op
+ }
+ });
+ return;
+ }
+ if (mPm.mProtectedPackages.isPackageDataProtected(user, packageName)) {
+ mPm.mHandler.post(() -> {
+ try {
+ Slog.w(TAG, "Attempted to delete protected package: " + packageName);
+ observer.onPackageDeleted(packageName,
+ PackageManager.DELETE_FAILED_INTERNAL_ERROR, null);
+ } catch (RemoteException re) {
+ // no-op
+ }
+ });
+ return;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
mPm.mHandler.post(() -> {
try {
diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
index dbf0d29..8ebb6ea 100644
--- a/services/core/java/com/android/server/pm/DistractingPackageHelper.java
+++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java
@@ -32,6 +32,7 @@
import com.android.server.pm.pkg.PackageStateInternal;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -133,6 +134,39 @@
return unactionedPackages.toArray(new String[0]);
}
+
+ /**
+ * Gets {@link DistractionRestriction restrictions} of the given packages of the given user.
+ *
+ * The corresponding element of the resulting array will be -1 if a given package doesn't exist.
+ *
+ * @param packageNames The packages under which to check.
+ * @param userId The user under which to check.
+ * @return an array of distracting restriction state in order of the given packages
+ */
+ int[] getDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
+ @NonNull String[] packageNames, int userId, int callingUid) {
+ int[] res = new int[packageNames.length];
+ Arrays.fill(res, -1);
+
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return res;
+ }
+
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateForInstalledAndFiltered(
+ packageName, callingUid, userId);
+ if (packageState == null) {
+ continue;
+ }
+
+ res[i] = packageState.getUserStateOrDefault(userId).getDistractionFlags();
+ }
+ return res;
+ }
+
/**
* Removes any {@link DistractionRestriction restrictions} set on given packages.
*
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 68c8abf..9ac983d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -399,7 +399,7 @@
args[j] = mArgs.get(i + j);
}
final CreateAppDataResult[] results = installer.createAppDataBatched(args);
- for (int j = 0; j < args.length; j++) {
+ for (int j = 0; j < results.length; j++) {
final CreateAppDataResult result = results[j];
final CompletableFuture<Long> future = mFutures.get(i + j);
if (result.exceptionCode == 0) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 8f70c77..23608c5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -705,9 +705,30 @@
@Override
public void verifySession() {
assertCallerIsOwnerOrRootOrSystem();
- Preconditions.checkArgument(isCommitted());
- Preconditions.checkArgument(!isInTerminalState());
- verify();
+ if (isCommittedAndNotInTerminalState()) {
+ verify();
+ }
+ }
+
+ private boolean isCommittedAndNotInTerminalState() {
+ String errorMsg = null;
+ if (!isCommitted()) {
+ errorMsg = TextUtils.formatSimple("The session %d should be committed", sessionId);
+ } else if (isSessionApplied()) {
+ errorMsg = TextUtils.formatSimple("The session %d has applied", sessionId);
+ } else if (isSessionFailed()) {
+ synchronized (PackageInstallerSession.this.mLock) {
+ errorMsg = TextUtils.formatSimple("The session %d has failed with error: %s",
+ sessionId, PackageInstallerSession.this.mSessionErrorMessage);
+ }
+ }
+ if (errorMsg != null) {
+ Slog.e(TAG, "verifySession error: " + errorMsg);
+ setSessionFailed(INSTALL_FAILED_INTERNAL_ERROR, errorMsg);
+ onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg);
+ return false;
+ }
+ return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f880c57..3377f00 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6793,6 +6793,16 @@
mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
true /* killApp */));
}
+
+ @Override
+ public int[] getDistractingPackageRestrictionsAsUser(
+ @NonNull String[] packageNames, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ return mDistractingPackageHelper.getDistractingPackageRestrictionsAsUser(snapshot,
+ packageNames, userId, callingUid);
+ }
}
private void setEnabledOverlayPackages(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3823e16..e4692f1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -23,6 +23,9 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+import static android.content.pm.PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
@@ -290,6 +293,8 @@
return runSuspend(false);
case "set-distracting-restriction":
return runSetDistractingRestriction();
+ case "get-distracting-restriction":
+ return runGetDistractingRestriction();
case "grant":
return runGrantRevokePermission(true);
case "revoke":
@@ -2585,6 +2590,58 @@
}
}
+ private int runGetDistractingRestriction() {
+ final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final List<String> packageNames = getRemainingArgs();
+ if (packageNames.isEmpty()) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+ pw.println("Distracting restrictions state for user " + userId);
+
+ final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
+ "get-distracting");
+ final String[] packages = packageNames.toArray(new String[]{});
+ int[] res = mPm.getDistractingPackageRestrictionsAsUser(packages, translatedUserId);
+
+ for (int i = 0; i < res.length; i++) {
+ final int state = res[i];
+ if (state == -1) {
+ pw.println(packages[i] + " not found ...");
+ } else {
+ pw.println(packages[i] + " state: " + stateToString(state));
+ }
+ }
+
+ return 0;
+ }
+
+ private static String stateToString(@PackageManager.DistractionRestriction int flag) {
+ switch (flag) {
+ case RESTRICTION_NONE:
+ return "NONE";
+ case RESTRICTION_HIDE_FROM_SUGGESTIONS:
+ return "HIDE_FROM_SUGGESTIONS";
+ case RESTRICTION_HIDE_NOTIFICATIONS:
+ return "HIDE_NOTIFICATIONS";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
private int runSuspend(boolean suspendedState) {
final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
@@ -4269,7 +4326,7 @@
pw.println(" [--preload] [--instant] [--full] [--dont-kill]");
pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
- pw.println(" [--apex] [--staged-ready-timeout TIMEOUT]");
+ pw.println(" [--apex] [--force-non-staged] [--staged-ready-timeout TIMEOUT]");
pw.println(" [PATH [SPLIT...]|-]");
pw.println(" Install an application. Must provide the apk data to install, either as");
pw.println(" file path(s) or '-' to read from stdin. Options are:");
@@ -4298,6 +4355,8 @@
pw.println(" --update-ownership: request the update ownership enforcement");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk");
+ pw.println(" --force-non-staged: force the installation to run under a non-staged");
+ pw.println(" session, which may complete without requiring a reboot");
pw.println(" --staged-ready-timeout: By default, staged sessions wait "
+ DEFAULT_STAGED_READY_TIMEOUT_MS);
pw.println(" milliseconds for pre-reboot verification to complete when");
@@ -4396,6 +4455,9 @@
pw.println(" Any existing flags are overwritten, which also means that if no flags are");
pw.println(" specified then all existing flags will be cleared.");
pw.println("");
+ pw.println(" get-distracting-restriction [--user USER_ID] PACKAGE [PACKAGE...]");
+ pw.println(" Gets the specified restriction flags of given package(s) (of the user).");
+ pw.println("");
pw.println(" grant [--user USER_ID] PACKAGE PERMISSION");
pw.println(" revoke [--user USER_ID] PACKAGE PERMISSION");
pw.println(" These commands either grant or revoke permissions to apps. The permissions");
diff --git a/services/core/java/com/android/server/pm/ResilientAtomicFile.java b/services/core/java/com/android/server/pm/ResilientAtomicFile.java
index 54ca426..3aefc5a 100644
--- a/services/core/java/com/android/server/pm/ResilientAtomicFile.java
+++ b/services/core/java/com/android/server/pm/ResilientAtomicFile.java
@@ -107,10 +107,15 @@
// In case of MT access, it's possible the files get overwritten during write.
// Let's open all FDs we need now.
- mMainOutStream = new FileOutputStream(mFile);
- mMainInStream = new FileInputStream(mFile);
- mReserveOutStream = new FileOutputStream(mReserveCopy);
- mReserveInStream = new FileInputStream(mReserveCopy);
+ try {
+ mMainOutStream = new FileOutputStream(mFile);
+ mMainInStream = new FileInputStream(mFile);
+ mReserveOutStream = new FileOutputStream(mReserveCopy);
+ mReserveInStream = new FileInputStream(mReserveCopy);
+ } catch (IOException e) {
+ close();
+ throw e;
+ }
return mMainOutStream;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 20abfe6..de7b687 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1747,6 +1747,10 @@
final String packageName = pkg.getPackageName();
for (final String permName : pkg.getRequestedPermissions()) {
+ if (mIsLeanback && NOTIFICATION_PERMISSIONS.contains(permName)) {
+ // Do not reset the Notification permissions on TV
+ continue;
+ }
final boolean isRuntimePermission;
synchronized (mLock) {
final Permission permission = mRegistry.getPermission(permName);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
new file mode 100644
index 0000000..4e72fae
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.os.Trace;
+import android.permission.IOnPermissionsChangeListener;
+
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Surrounds all PermissionManagerServiceInterface method calls with Trace.traceBegin and
+ * Trace.traceEnd. These traces are used for identifying permission issues and testing.
+ */
+public class PermissionManagerServiceTracingDecorator implements PermissionManagerServiceInterface {
+ private static final long TRACE_TAG = Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+ @NonNull
+ private final PermissionManagerServiceInterface mService;
+
+ public PermissionManagerServiceTracingDecorator(
+ @NonNull PermissionManagerServiceInterface service
+ ) {
+ mService = service;
+ }
+
+ @Nullable
+ @Override
+ public byte[] backupRuntimePermissions(int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#backupRuntimePermissions");
+ try {
+ return mService.backupRuntimePermissions(userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void restoreRuntimePermissions(@NonNull byte[] backup, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#restoreRuntimePermissions");
+ try {
+ mService.restoreRuntimePermissions(backup, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void restoreDelayedRuntimePermissions(@NonNull String packageName, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#restoreDelayedRuntimePermissions");
+ try {
+ mService.restoreDelayedRuntimePermissions(packageName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#dump");
+ try {
+ mService.dump(fd, pw, args);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAllPermissionGroups");
+ try {
+ return mService.getAllPermissionGroups(flags);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getPermissionGroupInfo");
+ try {
+ return mService.getPermissionGroupInfo(groupName, flags);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public PermissionInfo getPermissionInfo(@NonNull String permName, int flags,
+ @NonNull String opPackageName) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionInfo");
+ try {
+ return mService.getPermissionInfo(permName, flags, opPackageName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public List<PermissionInfo> queryPermissionsByGroup(String groupName, int flags) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#queryPermissionsByGroup");
+ try {
+ return mService.queryPermissionsByGroup(groupName, flags);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean addPermission(PermissionInfo info, boolean async) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#addPermission");
+ try {
+ return mService.addPermission(info, async);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void removePermission(String permName) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#removePermission");
+ try {
+ mService.removePermission(permName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public int getPermissionFlags(String packageName, String permName, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
+ try {
+ return mService.getPermissionFlags(packageName, permName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void updatePermissionFlags(String packageName, String permName, int flagMask,
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
+ try {
+ mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
+ checkAdjustPolicyFlagPermission, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#updatePermissionFlagsForAllApps");
+ try {
+ mService.updatePermissionFlagsForAllApps(flagMask, flagValues, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#addOnPermissionsChangeListener");
+ try {
+ mService.addOnPermissionsChangeListener(listener);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void removeOnPermissionsChangeListener(
+ IOnPermissionsChangeListener listener) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#removeOnPermissionsChangeListener");
+ try {
+ mService.removeOnPermissionsChangeListener(listener);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean addAllowlistedRestrictedPermission(@NonNull String packageName,
+ @NonNull String permName, int flags, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#addAllowlistedRestrictedPermission");
+ try {
+ return mService.addAllowlistedRestrictedPermission(packageName, permName, flags,
+ userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public List<String> getAllowlistedRestrictedPermissions(@NonNull String packageName, int flags,
+ int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAllowlistedRestrictedPermissions");
+ try {
+ return mService.getAllowlistedRestrictedPermissions(packageName, flags, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean removeAllowlistedRestrictedPermission(@NonNull String packageName,
+ @NonNull String permName, int flags, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#removeAllowlistedRestrictedPermission");
+ try {
+ return mService.removeAllowlistedRestrictedPermission(packageName, permName, flags,
+ userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
+ try {
+ mService.grantRuntimePermission(packageName, permName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
+ try {
+ mService.revokeRuntimePermission(packageName, permName, userId, reason);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl"
+ + "#revokePostNotificationPermissionWithoutKillForTest");
+ try {
+ mService.revokePostNotificationPermissionWithoutKillForTest(packageName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
+ int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
+ try {
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
+ try {
+ return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public List<SplitPermissionInfoParcelable> getSplitPermissions() {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getSplitPermissions");
+ try {
+ return mService.getSplitPermissions();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public int checkPermission(String pkgName, String permName, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
+ try {
+ return mService.checkPermission(pkgName, permName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public int checkUidPermission(int uid, String permName) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
+ try {
+ return mService.checkUidPermission(uid, permName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public Map<String, Set<String>> getAllAppOpPermissionPackages() {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAllAppOpPermissionPackages");
+ try {
+ return mService.getAllAppOpPermissionPackages();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public boolean isPermissionsReviewRequired(@NonNull String packageName, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#isPermissionsReviewRequired");
+ try {
+ return mService.isPermissionsReviewRequired(packageName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void resetRuntimePermissions(@NonNull AndroidPackage pkg, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#resetRuntimePermissions");
+ try {
+ mService.resetRuntimePermissions(pkg, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void resetRuntimePermissionsForUser(int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#resetRuntimePermissionsForUser");
+ try {
+ mService.resetRuntimePermissionsForUser(userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void readLegacyPermissionStateTEMP() {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#readLegacyPermissionStateTEMP");
+ try {
+ mService.readLegacyPermissionStateTEMP();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void writeLegacyPermissionStateTEMP() {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#writeLegacyPermissionStateTEMP");
+ try {
+ mService.writeLegacyPermissionStateTEMP();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Set<String> getInstalledPermissions(@NonNull String packageName) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getInstalledPermissions");
+ try {
+ return mService.getInstalledPermissions(packageName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Set<String> getGrantedPermissions(@NonNull String packageName, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getGrantedPermissions");
+ try {
+ return mService.getGrantedPermissions(packageName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public int[] getPermissionGids(@NonNull String permissionName, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionGids");
+ try {
+ return mService.getPermissionGids(permissionName, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAppOpPermissionPackages");
+ try {
+ return mService.getAppOpPermissionPackages(permissionName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Nullable
+ @Override
+ public Permission getPermissionTEMP(@NonNull String permName) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionTEMP");
+ try {
+ return mService.getPermissionTEMP(permName);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public List<PermissionInfo> getAllPermissionsWithProtection(int protection) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAllPermissionsWithProtection");
+ try {
+ return mService.getAllPermissionsWithProtection(protection);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public List<PermissionInfo> getAllPermissionsWithProtectionFlags(int protectionFlags) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getAllPermissionsWithProtectionFlags");
+ try {
+ return mService.getAllPermissionsWithProtectionFlags(protectionFlags);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public List<LegacyPermission> getLegacyPermissions() {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getLegacyPermissions");
+ try {
+ return mService.getLegacyPermissions();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public LegacyPermissionState getLegacyPermissionState(int appId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getLegacyPermissionState");
+ try {
+ return mService.getLegacyPermissionState(appId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void readLegacyPermissionsTEMP(
+ @NonNull LegacyPermissionSettings legacyPermissionSettings) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#readLegacyPermissionsTEMP");
+ try {
+ mService.readLegacyPermissionsTEMP(legacyPermissionSettings);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void writeLegacyPermissionsTEMP(
+ @NonNull LegacyPermissionSettings legacyPermissionSettings) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#writeLegacyPermissionsTEMP");
+ try {
+ mService.writeLegacyPermissionsTEMP(legacyPermissionSettings);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Nullable
+ @Override
+ public String getDefaultPermissionGrantFingerprint(int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#getDefaultPermissionGrantFingerprint");
+ try {
+ return mService.getDefaultPermissionGrantFingerprint(userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void setDefaultPermissionGrantFingerprint(@NonNull String fingerprint, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#setDefaultPermissionGrantFingerprint");
+ try {
+ mService.setDefaultPermissionGrantFingerprint(fingerprint, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onSystemReady() {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onSystemReady");
+ try {
+ mService.onSystemReady();
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onStorageVolumeMounted(@NonNull String volumeUuid, boolean fingerprintChanged) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#onStorageVolumeMounted");
+ try {
+ mService.onStorageVolumeMounted(volumeUuid, fingerprintChanged);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @NonNull
+ @Override
+ public int[] getGidsForUid(int uid) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getGidsForUid");
+ try {
+ return mService.getGidsForUid(uid);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onUserCreated(int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onUserCreated");
+ try {
+ mService.onUserCreated(userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onUserRemoved(int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onUserRemoved");
+ try {
+ mService.onUserRemoved(userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onPackageAdded(@NonNull PackageState packageState, boolean isInstantApp,
+ @Nullable AndroidPackage oldPkg) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onPackageAdded");
+ try {
+ mService.onPackageAdded(packageState, isInstantApp, oldPkg);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onPackageInstalled(@NonNull AndroidPackage pkg, int previousAppId,
+ @NonNull PermissionManagerServiceInternal.PackageInstalledParams params, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onPackageInstalled");
+ try {
+ mService.onPackageInstalled(pkg, previousAppId, params, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onPackageRemoved(@NonNull AndroidPackage pkg) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#onPackageRemoved");
+ try {
+ mService.onPackageRemoved(pkg);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
+ public void onPackageUninstalled(@NonNull String packageName, int appId,
+ @NonNull PackageState packageState, @Nullable AndroidPackage pkg,
+ @NonNull List<AndroidPackage> sharedUserPkgs, int userId) {
+ Trace.traceBegin(TRACE_TAG,
+ "TaggedTracingPermissionManagerServiceImpl#onPackageUninstalled");
+ try {
+ mService.onPackageUninstalled(packageName, appId, packageState, pkg, sharedUserPkgs,
+ userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index f839648..fc74a195 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -35,7 +35,7 @@
*/
public interface PackageStateInternal extends PackageState {
- @NonNull
+ @Nullable
AndroidPackageInternal getPkg();
// TODO: Remove in favor of exposing APIs directly?
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a075655..4957eaf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -266,7 +266,13 @@
// Whether to allow devices placed in vr headset viewers to have an alternative Home intent.
static final boolean ENABLE_VR_HEADSET_HOME_CAPTURE = true;
+ // --------- Key behavior definitions below. ---------
+ // NOTE: When updating the valid range of any of these behaviors, and if that behavior has a
+ // Settings key associated to it for dynamic update, update its valid Settings value range in
+ // android.provider.settings.validators.GlobalSettingsValidators.
+
// must match: config_shortPressOnPowerBehavior in config.xml
+ // The config value can be overridden using Settings.Global.POWER_BUTTON_SHORT_PRESS
static final int SHORT_PRESS_POWER_NOTHING = 0;
static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -277,6 +283,7 @@
static final int SHORT_PRESS_POWER_DREAM_OR_SLEEP = 7;
// must match: config_LongPressOnPowerBehavior in config.xml
+ // The config value can be overridden using Settings.Global.POWER_BUTTON_LONG_PRESS
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -285,6 +292,7 @@
static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT
// must match: config_veryLongPresOnPowerBehavior in config.xml
+ // The config value can be overridden using Settings.Global.POWER_BUTTON_VERY_LONG_PRESS
static final int VERY_LONG_PRESS_POWER_NOTHING = 0;
static final int VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
@@ -294,6 +302,8 @@
static final int POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS = 2;
// must match: config_doublePressOnPowerBehavior in config.xml
+ // The config value can be overridden using Settings.Global.POWER_BUTTON_DOUBLE_PRESS and/or
+ // Settings.Global.POWER_BUTTON_TRIPLE_PRESS
static final int MULTI_PRESS_POWER_NOTHING = 0;
static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
@@ -324,18 +334,22 @@
static final int PENDING_KEY_NULL = -1;
// Must match: config_shortPressOnStemPrimaryBehavior in config.xml
+ // The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS
static final int SHORT_PRESS_PRIMARY_NOTHING = 0;
static final int SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS = 1;
// Must match: config_longPressOnStemPrimaryBehavior in config.xml
+ // The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS
static final int LONG_PRESS_PRIMARY_NOTHING = 0;
static final int LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT = 1;
// Must match: config_doublePressOnStemPrimaryBehavior in config.xml
+ //The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS
static final int DOUBLE_PRESS_PRIMARY_NOTHING = 0;
static final int DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP = 1;
// Must match: config_triplePressOnStemPrimaryBehavior in config.xml
+ // The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_TRIPLE_PRESS
static final int TRIPLE_PRESS_PRIMARY_NOTHING = 0;
static final int TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY = 1;
@@ -804,6 +818,15 @@
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.POWER_BUTTON_SHORT_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.POWER_BUTTON_DOUBLE_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.POWER_BUTTON_TRIPLE_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POWER_BUTTON_LONG_PRESS), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -813,6 +836,18 @@
Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.STEM_PRIMARY_BUTTON_TRIPLE_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.KEY_CHORD_POWER_VOLUME_UP), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -985,6 +1020,9 @@
}
private void interceptPowerKeyUp(KeyEvent event, boolean canceled) {
+ // Inform the StatusBar; but do not allow it to consume the event.
+ sendSystemKeyToStatusBarAsync(event);
+
final boolean handled = canceled || mPowerKeyHandled;
if (!handled) {
@@ -2193,33 +2231,19 @@
mLongPressOnBackBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnBackBehavior);
- mShortPressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_shortPressOnPowerBehavior);
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
mLongPressOnPowerAssistantTimeoutMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerDurationMs);
mVeryLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_veryLongPressOnPowerBehavior);
- mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_doublePressOnPowerBehavior);
mPowerDoublePressTargetActivity = ComponentName.unflattenFromString(
mContext.getResources().getString(
com.android.internal.R.string.config_doublePressOnPowerTargetActivity));
- mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_triplePressOnPowerBehavior);
mShortPressOnSleepBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
- mShortPressOnStemPrimaryBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior);
- mLongPressOnStemPrimaryBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnStemPrimaryBehavior);
- mDoublePressOnStemPrimaryBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_doublePressOnStemPrimaryBehavior);
- mTriplePressOnStemPrimaryBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_triplePressOnStemPrimaryBehavior);
mHapticTextHandleEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
@@ -2681,6 +2705,19 @@
updateRotation = true;
}
+ mShortPressOnPowerBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.POWER_BUTTON_SHORT_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortPressOnPowerBehavior));
+ mDoublePressOnPowerBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.POWER_BUTTON_DOUBLE_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_doublePressOnPowerBehavior));
+ mTriplePressOnPowerBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.POWER_BUTTON_TRIPLE_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_triplePressOnPowerBehavior));
+
final int longPressOnPowerBehavior = Settings.Global.getInt(resolver,
Settings.Global.POWER_BUTTON_LONG_PRESS,
mContext.getResources().getInteger(
@@ -2706,6 +2743,25 @@
mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyChordPowerVolumeUp));
+ mShortPressOnStemPrimaryBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior));
+ mDoublePressOnStemPrimaryBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer
+ .config_doublePressOnStemPrimaryBehavior));
+ mTriplePressOnStemPrimaryBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.STEM_PRIMARY_BUTTON_TRIPLE_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer
+ .config_triplePressOnStemPrimaryBehavior));
+ mLongPressOnStemPrimaryBehavior = Settings.Global.getInt(resolver,
+ Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS,
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnStemPrimaryBehavior));
+
mStylusButtonsEnabled = Settings.Secure.getIntForUser(resolver,
Secure.STYLUS_BUTTONS_ENABLED, 1, UserHandle.USER_CURRENT) == 1;
mInputManagerInternal.setStylusButtonMotionEventsEnabled(mStylusButtonsEnabled);
@@ -3357,12 +3413,6 @@
Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"
+ " interceptKeyBeforeQueueing");
return key_consumed;
- case KeyEvent.KEYCODE_MACRO_1:
- case KeyEvent.KEYCODE_MACRO_2:
- case KeyEvent.KEYCODE_MACRO_3:
- case KeyEvent.KEYCODE_MACRO_4:
- Slog.wtf(TAG, "KEYCODE_MACRO_x should be handled in interceptKeyBeforeQueueing");
- return key_consumed;
}
if (isValidGlobalKey(keyCode)
@@ -4512,9 +4562,11 @@
case KeyEvent.KEYCODE_MACRO_2:
case KeyEvent.KEYCODE_MACRO_3:
case KeyEvent.KEYCODE_MACRO_4:
- // TODO(b/266098478): Add logic to handle KEYCODE_MACROx feature
result &= ~ACTION_PASS_TO_USER;
break;
+ case KeyEvent.KEYCODE_STEM_PRIMARY:
+ sendSystemKeyToStatusBarAsync(event);
+ break;
}
if (useHapticFeedback) {
@@ -4685,7 +4737,8 @@
if ((policyFlags & FLAG_WAKE) != 0) {
if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
- return 0;
+ // Woke up. Pass motion events to user.
+ return ACTION_PASS_TO_USER;
}
}
@@ -4697,8 +4750,11 @@
// there will be no dream to intercept the touch and wake into ambient. The device should
// wake up in this case.
if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
- wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
- PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION");
+ if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
+ PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
+ // Woke up. Pass motion events to user.
+ return ACTION_PASS_TO_USER;
+ }
}
return 0;
@@ -4714,28 +4770,19 @@
final boolean displayOff = (display == null
|| display.getState() == STATE_OFF);
- if (displayOff && !mHasFeatureWatch) {
+ if (displayOff) {
return false;
}
// Send events to keyguard while the screen is on and it's showing.
- if (isKeyguardShowingAndNotOccluded() && !displayOff) {
+ if (isKeyguardShowingAndNotOccluded()) {
return true;
}
- // Watches handle BACK and hardware buttons specially
- if (mHasFeatureWatch && (keyCode == KeyEvent.KEYCODE_BACK
- || keyCode == KeyEvent.KEYCODE_STEM_PRIMARY
- || keyCode == KeyEvent.KEYCODE_STEM_1
- || keyCode == KeyEvent.KEYCODE_STEM_2
- || keyCode == KeyEvent.KEYCODE_STEM_3)) {
- return false;
- }
-
// TODO(b/123372519): Refine when dream can support multi display.
if (isDefaultDisplay) {
- // Send events to a dozing dream even if the screen is off since the dream
- // is in control of the state of the screen.
+ // Send events to a dozing dream since the dream is in control of the state of the
+ // screen.
IDreamManager dreamManager = getDreamManager();
try {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index efb3622..07d1844 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -19,6 +19,7 @@
import android.app.UiModeManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatterySaverPolicyConfig;
@@ -162,26 +163,8 @@
private static final Policy DEFAULT_ADAPTIVE_POLICY = OFF_POLICY;
- private static final Policy DEFAULT_FULL_POLICY = new Policy(
- 0.5f, /* adjustBrightnessFactor */
- true, /* advertiseIsEnabled */
- true, /* deferFullBackup */
- true, /* deferKeyValueBackup */
- false, /* disableAnimation */
- true, /* disableAod */
- true, /* disableLaunchBoost */
- true, /* disableOptionalSensors */
- false, /* disableVibration */
- false, /* enableAdjustBrightness */
- false, /* enableDataSaver */
- true, /* enableFirewall */
- true, /* enableNightMode */
- true, /* enableQuickDoze */
- true, /* forceAllAppsStandby */
- true, /* forceBackgroundCheck */
- PowerManager.LOCATION_MODE_FOREGROUND_ONLY, /* locationMode */
- PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY /* soundTriggerMode */
- );
+ /** The base default full policy for the device. */
+ private final Policy DEFAULT_FULL_POLICY;
private final Object mLock;
private final Handler mHandler;
@@ -222,13 +205,13 @@
@GuardedBy("mLock")
private Policy mAdaptivePolicy = DEFAULT_ADAPTIVE_POLICY;
- /** The current default full policy. */
+ /** The current default full policy. This may be modified by Settings or DeviceConfig flags. */
@GuardedBy("mLock")
- private Policy mDefaultFullPolicy = DEFAULT_FULL_POLICY;
+ private Policy mDefaultFullPolicy;
/** The policy to be used for full battery saver. */
@GuardedBy("mLock")
- private Policy mFullPolicy = DEFAULT_FULL_POLICY;
+ private Policy mFullPolicy;
/**
* The current effective policy. This is based on the current policy level's policy, with any
@@ -273,6 +256,30 @@
mContext = context;
mContentResolver = context.getContentResolver();
mBatterySavingStats = batterySavingStats;
+
+ final Resources res = context.getResources();
+ DEFAULT_FULL_POLICY = new Policy(
+ res.getFloat(R.dimen.config_batterySaver_full_adjustBrightnessFactor),
+ true, /* advertiseIsEnabled */
+ res.getBoolean(R.bool.config_batterySaver_full_deferFullBackup),
+ res.getBoolean(R.bool.config_batterySaver_full_deferKeyValueBackup),
+ res.getBoolean(R.bool.config_batterySaver_full_disableAnimation),
+ res.getBoolean(R.bool.config_batterySaver_full_disableAod),
+ res.getBoolean(R.bool.config_batterySaver_full_disableLaunchBoost),
+ res.getBoolean(R.bool.config_batterySaver_full_disableOptionalSensors),
+ res.getBoolean(R.bool.config_batterySaver_full_disableVibration),
+ res.getBoolean(R.bool.config_batterySaver_full_enableAdjustBrightness),
+ res.getBoolean(R.bool.config_batterySaver_full_enableDataSaver),
+ res.getBoolean(R.bool.config_batterySaver_full_enableFirewall),
+ res.getBoolean(R.bool.config_batterySaver_full_enableNightMode),
+ res.getBoolean(R.bool.config_batterySaver_full_enableQuickDoze),
+ res.getBoolean(R.bool.config_batterySaver_full_forceAllAppsStandby),
+ res.getBoolean(R.bool.config_batterySaver_full_forceBackgroundCheck),
+ res.getInteger(R.integer.config_batterySaver_full_locationMode),
+ res.getInteger(R.integer.config_batterySaver_full_soundTriggerMode)
+ );
+ mDefaultFullPolicy = DEFAULT_FULL_POLICY;
+ mFullPolicy = DEFAULT_FULL_POLICY;
}
/**
diff --git a/services/core/java/com/android/server/power/batterysaver/OWNERS b/services/core/java/com/android/server/power/batterysaver/OWNERS
index 09136dc..cf23bea 100644
--- a/services/core/java/com/android/server/power/batterysaver/OWNERS
+++ b/services/core/java/com/android/server/power/batterysaver/OWNERS
@@ -1 +1,3 @@
+kwekua@google.com
omakoto@google.com
+yamasani@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index fae6262..1fed7129 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -1033,6 +1033,7 @@
private static final int USB_DATA_CONNECTED = 2;
int mUsbDataState = USB_DATA_UNKNOWN;
+ private static final int GPS_SIGNAL_QUALITY_NONE = 2;
int mGpsSignalQualityBin = -1;
final StopwatchTimer[] mGpsSignalQualityTimer =
new StopwatchTimer[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
@@ -5222,6 +5223,8 @@
if (mGpsNesting == 0) {
mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs,
HistoryItem.STATE_GPS_ON_FLAG);
+ mHistory.recordGpsSignalQualityEvent(elapsedRealtimeMs, uptimeMs,
+ GPS_SIGNAL_QUALITY_NONE);
stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs);
mGpsSignalQualityBin = -1;
}
diff --git a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
index 00bedac..6677e7e 100644
--- a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
+++ b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
@@ -37,8 +37,8 @@
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
-import android.permission.PermissionManager;
import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -294,8 +294,8 @@
BoundServiceInfo serviceInfo = new BoundServiceInfo(mIntent.getAction(), resolveInfo);
if (mServicePermission != null) {
- if (PermissionManager.checkPackageNamePermission(mServicePermission,
- service.packageName, serviceInfo.getUserId()) != PERMISSION_GRANTED) {
+ if (mContext.checkPermission(mServicePermission, Process.INVALID_PID,
+ serviceInfo.mUid) != PERMISSION_GRANTED) {
Log.d(TAG, serviceInfo.getComponentName().flattenToShortString()
+ " disqualified due to not holding " + mCallerPermission);
continue;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index efd8b6d..6e9a22c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.ITransientNotificationCallback;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
import android.os.IBinder;
import android.view.WindowInsets.Type.InsetsType;
@@ -54,13 +55,13 @@
* @param displayId The display to which the IME is bound to.
* @param token The IME token.
* @param vis Bit flags about the IME visibility.
- * (e.g. {@link android.inputmethodservice.InputMethodService#IME_ACTIVE})
* @param backDisposition Bit flags about the IME back disposition.
- * (e.g. {@link android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT})
* @param showImeSwitcher {@code true} when the IME switcher button should be shown.
*/
- void setImeWindowStatus(int displayId, IBinder token, int vis,
- int backDisposition, boolean showImeSwitcher);
+ void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
+ boolean showImeSwitcher);
/**
* See {@link android.app.StatusBarManager#setIcon(String, int, int, String)}.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 044d30b..719b2d2 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -59,6 +59,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.net.Uri;
@@ -516,7 +517,9 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ public void setImeWindowStatus(int displayId, IBinder token,
+ @InputMethodService.ImeWindowVisibility int vis,
+ @InputMethodService.BackDispositionMode int backDisposition,
boolean showImeSwitcher) {
StatusBarManagerService.this.setImeWindowStatus(displayId, token, vis, backDisposition,
showImeSwitcher);
@@ -1221,12 +1224,14 @@
}
@Override
- public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
- final int backDisposition, final boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, final IBinder token,
+ @InputMethodService.ImeWindowVisibility final int vis,
+ @InputMethodService.BackDispositionMode final int backDisposition,
+ final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
- Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
+ Slog.d(TAG, "setImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
}
synchronized(mLock) {
@@ -1289,7 +1294,9 @@
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
+ @InputMethodService.ImeWindowVisibility
private int mImeWindowVis = 0;
+ @InputMethodService.BackDispositionMode
private int mImeBackDisposition = 0;
private boolean mShowImeSwitcher = false;
private IBinder mImeToken = null;
@@ -1334,7 +1341,8 @@
return mDisabled1 == disabled1 && mDisabled2 == disabled2;
}
- private void setImeWindowState(final int vis, final int backDisposition,
+ private void setImeWindowState(@InputMethodService.ImeWindowVisibility final int vis,
+ @InputMethodService.BackDispositionMode final int backDisposition,
final boolean showImeSwitcher, final IBinder token) {
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
index 49b125c..b773ade 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -81,7 +81,7 @@
if (DEBUG) {
Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
+ Integer.toHexString(wallpaper.mWhich)
- + " to " + wallpaper.cropFile.getName()
+ + " to " + wallpaper.getCropFile().getName()
+ " crop=(" + cropHint.width() + 'x' + cropHint.height()
+ ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')');
}
@@ -89,7 +89,7 @@
// Analyse the source; needed in multiple cases
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+ BitmapFactory.decodeFile(wallpaper.getWallpaperFile().getAbsolutePath(), options);
if (options.outWidth <= 0 || options.outHeight <= 0) {
Slog.w(TAG, "Invalid wallpaper data");
success = false;
@@ -154,11 +154,10 @@
// may be we can try to remove this optimized way in the future,
// that means, we will always go into the 'else' block.
- success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+ success = FileUtils.copyFile(wallpaper.getWallpaperFile(), wallpaper.getCropFile());
if (!success) {
- wallpaper.cropFile.delete();
- // TODO: fall back to default wallpaper in this case
+ wallpaper.getCropFile().delete();
}
if (DEBUG) {
@@ -226,7 +225,7 @@
//Create a record file and will delete if ImageDecoder work well.
final String recordName =
- (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
+ (wallpaper.getWallpaperFile().getName().equals(WALLPAPER)
? RECORD_FILE : RECORD_LOCK_FILE);
final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
record.createNewFile();
@@ -234,7 +233,7 @@
+ ", record name =" + record.getName());
final ImageDecoder.Source srcData =
- ImageDecoder.createSource(wallpaper.wallpaperFile);
+ ImageDecoder.createSource(wallpaper.getWallpaperFile());
final int sampleSize = scale;
Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
decoder.setTargetSampleSize(sampleSize);
@@ -257,7 +256,7 @@
+ " h=" + finalCrop.getHeight());
}
- f = new FileOutputStream(wallpaper.cropFile);
+ f = new FileOutputStream(wallpaper.getCropFile());
bos = new BufferedOutputStream(f, 32 * 1024);
finalCrop.compress(Bitmap.CompressFormat.PNG, 100, bos);
// don't rely on the implicit flush-at-close when noting success
@@ -277,11 +276,11 @@
if (!success) {
Slog.e(TAG, "Unable to apply new wallpaper");
- wallpaper.cropFile.delete();
+ wallpaper.getCropFile().delete();
}
- if (wallpaper.cropFile.exists()) {
- boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+ if (wallpaper.getCropFile().exists()) {
+ boolean didRestorecon = SELinux.restorecon(wallpaper.getCropFile().getAbsoluteFile());
if (DEBUG) {
Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index d87fca4..b0b66cf 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -40,10 +40,7 @@
*/
class WallpaperData {
- int userId;
-
- final File wallpaperFile; // source image
- final File cropFile; // eventual destination
+ final int userId;
/**
* True while the client is writing a new wallpaper
@@ -133,14 +130,13 @@
*/
final Rect cropHint = new Rect(0, 0, 0, 0);
+ // map of which -> File
+ private final SparseArray<File> mWallpaperFiles = new SparseArray<>();
+ private final SparseArray<File> mCropFiles = new SparseArray<>();
+
WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) {
this.userId = userId;
this.mWhich = wallpaperType;
- File wallpaperDir = getWallpaperDir(userId);
- String wallpaperFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER;
- String cropFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP;
- this.wallpaperFile = new File(wallpaperDir, wallpaperFileName);
- this.cropFile = new File(wallpaperDir, cropFileName);
}
/**
@@ -154,8 +150,6 @@
*/
WallpaperData(WallpaperData source) {
this.userId = source.userId;
- this.wallpaperFile = source.wallpaperFile;
- this.cropFile = source.cropFile;
this.wallpaperComponent = source.wallpaperComponent;
this.mWhich = source.mWhich;
this.wallpaperId = source.wallpaperId;
@@ -169,6 +163,25 @@
}
}
+ File getWallpaperFile() {
+ String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_ORIG : WALLPAPER;
+ return getFile(mWallpaperFiles, fileName);
+ }
+
+ File getCropFile() {
+ String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP;
+ return getFile(mCropFiles, fileName);
+ }
+
+ private File getFile(SparseArray<File> map, String fileName) {
+ File result = map.get(mWhich);
+ if (result == null) {
+ result = new File(getWallpaperDir(userId), fileName);
+ map.put(userId, result);
+ }
+ return result;
+ }
+
@Override
public String toString() {
StringBuilder out = new StringBuilder(defaultString(this));
@@ -177,7 +190,7 @@
out.append(", which: ");
out.append(mWhich);
out.append(", file mod: ");
- out.append(wallpaperFile != null ? wallpaperFile.lastModified() : "null");
+ out.append(getWallpaperFile() != null ? getWallpaperFile().lastModified() : "null");
if (connection == null) {
out.append(", no connection");
} else {
@@ -202,10 +215,10 @@
// Called during initialization of a given user's wallpaper bookkeeping
boolean cropExists() {
- return cropFile.exists();
+ return getCropFile().exists();
}
boolean sourceExists() {
- return wallpaperFile.exists();
+ return getWallpaperFile().exists();
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index 1133dba..c54e3bd 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -542,12 +542,12 @@
}
res = r.openRawResource(resId);
- if (wallpaper.wallpaperFile.exists()) {
- wallpaper.wallpaperFile.delete();
- wallpaper.cropFile.delete();
+ if (wallpaper.getWallpaperFile().exists()) {
+ wallpaper.getWallpaperFile().delete();
+ wallpaper.getCropFile().delete();
}
- fos = new FileOutputStream(wallpaper.wallpaperFile);
- cos = new FileOutputStream(wallpaper.cropFile);
+ fos = new FileOutputStream(wallpaper.getWallpaperFile());
+ cos = new FileOutputStream(wallpaper.getCropFile());
byte[] buffer = new byte[32768];
int amt;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 1e9abd9..11d1126 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -675,8 +675,8 @@
// Not having a wallpaperComponent means it's a lock screen wallpaper.
final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
|| wallpaper.wallpaperComponent == null;
- if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
- cropFile = wallpaper.cropFile.getAbsolutePath();
+ if (imageWallpaper && wallpaper.getCropFile().exists()) {
+ cropFile = wallpaper.getCropFile().getAbsolutePath();
} else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
defaultImageWallpaper = true;
}
@@ -1839,8 +1839,8 @@
private boolean clearWallpaperBitmaps(WallpaperData wallpaper) {
boolean sourceExists = wallpaper.sourceExists();
boolean cropExists = wallpaper.cropExists();
- if (sourceExists) wallpaper.wallpaperFile.delete();
- if (cropExists) wallpaper.cropFile.delete();
+ if (sourceExists) wallpaper.getWallpaperFile().delete();
+ if (cropExists) wallpaper.getCropFile().delete();
return sourceExists || cropExists;
}
@@ -2439,13 +2439,13 @@
wallpaper.callbacks.register(cb);
}
- File fileToReturn = getCropped ? wallpaper.cropFile : wallpaper.wallpaperFile;
+ File result = getCropped ? wallpaper.getCropFile() : wallpaper.getWallpaperFile();
- if (!fileToReturn.exists()) {
+ if (!result.exists()) {
return null;
}
- return ParcelFileDescriptor.open(fileToReturn, MODE_READ_ONLY);
+ return ParcelFileDescriptor.open(result, MODE_READ_ONLY);
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
Slog.w(TAG, "Error getting wallpaper", e);
@@ -3206,16 +3206,17 @@
// Migrate the bitmap files outright; no need to copy
try {
- if (!mIsLockscreenLiveWallpaperEnabled || sysWP.wallpaperFile.exists()) {
- Os.rename(sysWP.wallpaperFile.getAbsolutePath(),
- lockWP.wallpaperFile.getAbsolutePath());
+ if (!mIsLockscreenLiveWallpaperEnabled || sysWP.getWallpaperFile().exists()) {
+ Os.rename(sysWP.getWallpaperFile().getAbsolutePath(),
+ lockWP.getWallpaperFile().getAbsolutePath());
}
- if (!mIsLockscreenLiveWallpaperEnabled || sysWP.cropFile.exists()) {
- Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
+ if (!mIsLockscreenLiveWallpaperEnabled || sysWP.getCropFile().exists()) {
+ Os.rename(sysWP.getCropFile().getAbsolutePath(),
+ lockWP.getCropFile().getAbsolutePath());
}
mLockWallpaperMap.put(userId, lockWP);
if (mIsLockscreenLiveWallpaperEnabled) {
- SELinux.restorecon(lockWP.wallpaperFile);
+ SELinux.restorecon(lockWP.getWallpaperFile());
mLastLockWallpaper = lockWP;
}
} catch (ErrnoException e) {
@@ -3236,11 +3237,11 @@
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.getWallpaperFile(),
MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
- if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
+ if (!SELinux.restorecon(wallpaper.getWallpaperFile())) {
Slog.w(TAG, "restorecon failed for wallpaper file: " +
- wallpaper.wallpaperFile.getPath());
+ wallpaper.getWallpaperFile().getPath());
return null;
}
wallpaper.name = name;
@@ -3251,7 +3252,7 @@
// Nullify field to require new computation
wallpaper.primaryColors = null;
Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
- + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
+ + " name=" + name + " file=" + wallpaper.getWallpaperFile().getName());
return fd;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Error setting wallpaper", e);
@@ -3415,7 +3416,7 @@
WallpaperData wallpaper;
synchronized (mLock) {
- Slog.v(TAG, "setWallpaperComponent name=" + name);
+ Slog.v(TAG, "setWallpaperComponent name=" + name + ", which=" + which);
wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -3446,7 +3447,11 @@
wallpaper.mWhich = which;
wallpaper.fromForegroundApp = isFromForegroundApp(callingPackage);
boolean same = changingToSame(name, wallpaper);
- if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+
+ // force rebind when reapplying a system-only wallpaper to system+lock
+ boolean forceRebind = same && mLockWallpaperMap.get(userId) != null
+ && which == (FLAG_SYSTEM | FLAG_LOCK);
+ if (bindWallpaperComponentLocked(name, forceRebind, true, wallpaper, null)) {
if (!same) {
wallpaper.primaryColors = null;
} else {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3be586e..3db423e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -223,6 +223,7 @@
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.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
@@ -8814,9 +8815,18 @@
final float letterboxAspectRatioOverride =
mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
- final float desiredAspectRatio =
- letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
+
+ // Aspect ratio as suggested by the system. Apps requested mix/max aspect ratio will
+ // be respected in #applyAspectRatio.
+ final float desiredAspectRatio;
+ if (isDefaultMultiWindowLetterboxAspectRatioDesired(newParentConfig)) {
+ desiredAspectRatio = DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
+ } else if (letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
+ desiredAspectRatio = letterboxAspectRatioOverride;
+ } else {
+ desiredAspectRatio = computeAspectRatio(parentBounds);
+ }
+
// Apply aspect ratio to resolved bounds
mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
containingBounds, desiredAspectRatio);
@@ -8842,6 +8852,20 @@
}
/**
+ * Returns {@code true} if the default aspect ratio for a letterboxed app in multi-window mode
+ * should be used.
+ */
+ private boolean isDefaultMultiWindowLetterboxAspectRatioDesired(
+ @NonNull Configuration parentConfig) {
+ if (mDisplayContent == null) {
+ return false;
+ }
+ final int windowingMode = parentConfig.windowConfiguration.getWindowingMode();
+ return WindowConfiguration.inMultiWindowMode(windowingMode)
+ && !mDisplayContent.getIgnoreOrientationRequest();
+ }
+
+ /**
* Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
* aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
* within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index dce3a38..d2715b6 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1587,21 +1587,14 @@
newTransition = null;
}
}
- if (isTransientLaunch) {
- if (forceTransientTransition) {
- transitionController.collect(mLastStartActivityRecord);
- transitionController.collect(mPriorAboveTask);
- }
- // `started` isn't guaranteed to be the actual relevant activity, so we must wait
- // until after we launched to identify the relevant activity.
- transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
- if (forceTransientTransition) {
- final DisplayContent dc = mLastStartActivityRecord.getDisplayContent();
- // update wallpaper target to TransientHide
- dc.mWallpaperController.adjustWallpaperWindows();
- // execute transition because there is no change
- transitionController.setReady(dc, true /* ready */);
- }
+ if (forceTransientTransition) {
+ transitionController.collect(mLastStartActivityRecord);
+ transitionController.collect(mPriorAboveTask);
+ final DisplayContent dc = mLastStartActivityRecord.getDisplayContent();
+ // update wallpaper target to TransientHide
+ dc.mWallpaperController.adjustWallpaperWindows();
+ // execute transition because there is no change
+ transitionController.setReady(dc, true /* ready */);
}
if (!userLeaving) {
// no-user-leaving implies not entering PiP.
@@ -1711,6 +1704,7 @@
activity.destroyIfPossible("Removes redundant singleInstance");
}
}
+ recordTransientLaunchIfNeeded(targetTaskTop);
// Recycle the target task for this launch.
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if (startResult != START_SUCCESS) {
@@ -1742,6 +1736,9 @@
addOrReparentStartingActivity(targetTask, "adding to task");
}
+ // After activity is attached to task, but before actual start
+ recordTransientLaunchIfNeeded(mLastStartActivityRecord);
+
if (!mAvoidMoveToFront && mDoResume) {
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
@@ -1838,6 +1835,14 @@
return START_SUCCESS;
}
+ private void recordTransientLaunchIfNeeded(ActivityRecord r) {
+ if (r == null || !mTransientLaunch) return;
+ final TransitionController controller = r.mTransitionController;
+ if (controller.isCollecting() && !controller.isTransientCollect(r)) {
+ controller.setTransientLaunch(r, mPriorAboveTask);
+ }
+ }
+
/** Returns the leaf task where the target activity may be placed. */
private Task computeTargetTask() {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4a658d6..41b3aad 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6068,6 +6068,12 @@
@Override
public void showSystemReadyErrorDialogsIfNeeded() {
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "showSystemReadyErrorDialogs");
+ }
+ // Pull the check for build consistency outside the lock, to avoid holding the lock for
+ // too long, given that `Build.isBuildConsistent()` takes relatively long.
+ boolean isBuildConsistent = Build.isBuildConsistent();
synchronized (mGlobalLock) {
try {
if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
@@ -6090,7 +6096,7 @@
} catch (RemoteException e) {
}
- if (!Build.isBuildConsistent()) {
+ if (!isBuildConsistent) {
Slog.e(TAG, "Build fingerprint is not consistent, warning user");
mUiHandler.post(() -> {
if (mShowDialogs) {
@@ -6107,6 +6113,7 @@
});
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@Override
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java
index db4762e..857e03d 100644
--- a/services/core/java/com/android/server/wm/DeviceStateController.java
+++ b/services/core/java/com/android/server/wm/DeviceStateController.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.util.ArrayMap;
+import android.util.Pair;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -165,19 +166,28 @@
// Make a copy here because it's possible that the consumer tries to remove a callback
// while we're still iterating through the list, which would end up in a
- // ConcurrentModificationException.
- final List<Map.Entry<Consumer<DeviceState>, Executor>> entries = new ArrayList<>();
- synchronized (mWmLock) {
- for (Map.Entry<Consumer<DeviceState>, Executor> entry
- : mDeviceStateCallbacks.entrySet()) {
- entries.add(entry);
- }
- }
+ // ConcurrentModificationException. Note that cannot use a List<Map.Entry> because the
+ // entries are tied to the backing map. So, if a client removes a callback while
+ // we are notifying clients, we will get a NPE.
+ final List<Pair<Consumer<DeviceState>, Executor>> entries = copyDeviceStateCallbacks();
for (int i = 0; i < entries.size(); i++) {
- Map.Entry<Consumer<DeviceState>, Executor> entry = entries.get(i);
- entry.getValue().execute(() -> entry.getKey().accept(mCurrentDeviceState));
+ final Pair<Consumer<DeviceState>, Executor> entry = entries.get(i);
+ entry.second.execute(() -> entry.first.accept(deviceState));
}
}
}
+
+ @VisibleForTesting
+ @NonNull
+ List<Pair<Consumer<DeviceState>, Executor>> copyDeviceStateCallbacks() {
+ final List<Pair<Consumer<DeviceState>, Executor>> entries = new ArrayList<>();
+
+ synchronized (mWmLock) {
+ mDeviceStateCallbacks.forEach((deviceStateConsumer, executor) -> {
+ entries.add(new Pair<>(deviceStateConsumer, executor));
+ });
+ }
+ return entries;
+ }
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 8660bec..89f044b 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -178,6 +178,10 @@
mSurfaceAnimatorStarter = surfaceAnimatorStarter;
}
+ WindowContainer<?> getHost() {
+ return mHost;
+ }
+
private SurfaceControl makeDimLayer() {
return mHost.makeChildSurface(null)
.setParent(mHost.getSurfaceControl())
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 9f59f5a..f81e5d4 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -790,7 +790,8 @@
// If SystemUI is dragging for recents, we want to reset the dim state so any dim layer
// on the display level fades out.
- if (forAllTasks(task -> !task.canAffectSystemUiFlags())) {
+ if (!mTransitionController.isShellTransitionsEnabled()
+ && forAllTasks(task -> !task.canAffectSystemUiFlags())) {
mDimmer.resetDimStates();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7fc86b0..2dc133f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -244,6 +244,7 @@
import android.window.DisplayWindowPolicyController;
import android.window.IDisplayAreaOrganizer;
import android.window.ScreenCapture;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import android.window.TransitionRequestInfo;
import com.android.internal.R;
@@ -1213,8 +1214,7 @@
mDisplayRotationCompatPolicy =
// Not checking DeviceConfig value here to allow enabling via DeviceConfig
// without the need to restart the device.
- mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ false)
+ mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabledAtBuildTime()
? new DisplayRotationCompatPolicy(this) : null;
mRotationReversionController = new DisplayRotationReversionController(this);
@@ -5088,7 +5088,7 @@
return null;
}
- Pair<ScreenCapture.ScreenCaptureListener, ScreenCapture.ScreenshotSync> syncScreenCapture =
+ SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
getBounds(mTmpRect);
@@ -5097,10 +5097,10 @@
new ScreenCapture.LayerCaptureArgs.Builder(getSurfaceControl())
.setSourceCrop(mTmpRect).build();
- ScreenCapture.captureLayers(args, syncScreenCapture.first);
+ ScreenCapture.captureLayers(args, syncScreenCapture);
final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
- syncScreenCapture.second.get();
+ syncScreenCapture.getBuffer();
final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
if (bitmap == null) {
Slog.w(TAG_WM, "Failed to take screenshot");
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 79657c3..a61be9e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1527,9 +1527,14 @@
}
} else if (win.isDimming()) {
if (mStatusBar != null) {
- if (addStatusBarAppearanceRegionsForDimmingWindow(
- win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS,
- mStatusBar.getFrame(), win.getBounds(), win.getFrame())) {
+ // If the dim window is below status bar window, we should update the appearance
+ // region if needed. Otherwise, leave it as it is.
+ final int statusBarLayer = mStatusBar.mToken.getWindowLayerFromType();
+ final int targetWindowLayer = win.mToken.getWindowLayerFromType();
+ if (targetWindowLayer < statusBarLayer
+ && addStatusBarAppearanceRegionsForDimmingWindow(
+ win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS,
+ mStatusBar.getFrame(), win.getBounds(), win.getFrame())) {
addSystemBarColorApp(win);
}
}
@@ -2371,7 +2376,8 @@
// We need to force the consumption of the system bars if they are force shown or if they
// are controlled by a remote insets controller.
mForceConsumeSystemBars = mForceShowSystemBars
- || mDisplayContent.getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win);
+ || getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win)
+ || getInsetsPolicy().forcesShowingNavigationBars(win);
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars());
@@ -2582,7 +2588,8 @@
if (win == null) {
return false;
}
- if (win == getNotificationShade() || win.isActivityTypeDream()) {
+ if (win.mPolicy.getWindowLayerLw(win) > win.mPolicy.getWindowLayerFromTypeLw(
+ WindowManager.LayoutParams.TYPE_STATUS_BAR) || win.isActivityTypeDream()) {
return false;
}
return getInsetsPolicy().hasHiddenSources(Type.navigationBars());
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 2b34bb2..f96f99d 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -336,8 +336,7 @@
* </ul>
*/
private boolean isTreatmentEnabledForDisplay() {
- return mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ true)
+ return mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabled()
&& mDisplayContent.getIgnoreOrientationRequest()
// TODO(b/225928882): Support camera compat rotation for external displays
&& mDisplayContent.getDisplay().getType() == TYPE_INTERNAL;
diff --git a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
index 74494dd..de70c4d 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
@@ -44,7 +44,7 @@
@NonNull final DisplayRotation displayRotation,
@NonNull final DisplayContent displayContent) {
if (!letterboxConfiguration
- .isDisplayRotationImmersiveAppCompatPolicyEnabled(/* checkDeviceConfig */ false)) {
+ .isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime()) {
return null;
}
@@ -87,8 +87,7 @@
* @return {@code true}, if there is a need to lock screen rotation, {@code false} otherwise.
*/
boolean isRotationLockEnforced(@Surface.Rotation final int proposedRotation) {
- if (!mLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled(
- /* checkDeviceConfig */ true)) {
+ if (!mLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled()) {
return false;
}
synchronized (mDisplayContent.mWmService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index cea886f..825d38b 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -49,6 +49,7 @@
import static java.lang.Integer.MAX_VALUE;
import android.annotation.Nullable;
+import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.IBinder;
@@ -558,7 +559,8 @@
private boolean mAddWallpaperInputConsumerHandle;
private boolean mAddRecentsAnimationInputConsumerHandle;
- boolean mInDrag;
+ private boolean mInDrag;
+ private final Rect mTmpRect = new Rect();
private void updateInputWindows(boolean inDrag) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
@@ -582,8 +584,11 @@
layer = layer != null ? layer : activeRecents;
// Handle edge-case for SUW where windows don't exist yet
if (layer.getSurfaceControl() != null) {
- mRecentsAnimationInputConsumer.mWindowHandle
- .replaceTouchableRegionWithCrop(layer.getSurfaceControl());
+ final WindowState targetAppMainWindow = activeRecents.findMainWindow();
+ if (targetAppMainWindow != null) {
+ targetAppMainWindow.getBounds(mTmpRect);
+ mRecentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
+ }
mRecentsAnimationInputConsumer.show(mInputTransaction, layer);
mAddRecentsAnimationInputConsumerHandle = false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 698c9ab..798dc85 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -567,8 +567,7 @@
return focusedWin;
}
}
- if (mPolicy.isForceShowNavigationBarEnabled() && focusedWin != null
- && focusedWin.getActivityType() == ACTIVITY_TYPE_STANDARD) {
+ if (forcesShowingNavigationBars(focusedWin)) {
// When "force show navigation bar" is enabled, it means both force visible is true, and
// we are in 3-button navigation. In this mode, the navigation bar is forcibly shown
// when activity type is ACTIVITY_TYPE_STANDARD which means Launcher or Recent could
@@ -604,6 +603,11 @@
return focusedWin;
}
+ boolean forcesShowingNavigationBars(WindowState win) {
+ return mPolicy.isForceShowNavigationBarEnabled() && win != null
+ && win.getActivityType() == ACTIVITY_TYPE_STANDARD;
+ }
+
/**
* Determines whether the remote insets controller should take control of system bars for all
* windows.
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ad9c3b2..671400c 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -671,8 +671,7 @@
display.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
- if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
- && mTopTurnScreenOnActivity != null
+ if (mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
&& (mRequestDismissKeyguard || occludedByActivity)) {
controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index a93cb8ad..fda22ca 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -18,11 +18,6 @@
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.LetterboxConfigurationDeviceConfig.KEY_ALLOW_IGNORE_ORIENTATION_REQUEST;
-import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_CAMERA_COMPAT_TREATMENT;
-import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_COMPAT_FAKE_FOCUS;
-import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY;
-import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -44,6 +39,52 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxConfiguration" : TAG_ATM;
+ // Whether camera compatibility treatment is enabled.
+ // See DisplayRotationCompatPolicy for context.
+ private static final String KEY_ENABLE_CAMERA_COMPAT_TREATMENT =
+ "enable_compat_camera_treatment";
+
+ private static final boolean DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT = true;
+
+ // Whether enabling rotation compat policy for immersive apps that prevents auto
+ // rotation into non-optimal screen orientation while in fullscreen. This is needed
+ // because immersive apps, such as games, are often not optimized for all
+ // orientations and can have a poor UX when rotated. Additionally, some games rely
+ // on sensors for the gameplay so users can trigger such rotations accidentally
+ // when auto rotation is on.
+ private static final String KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
+ "enable_display_rotation_immersive_app_compat_policy";
+
+ private static final boolean DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
+ true;
+
+ // Whether ignore orientation request is allowed
+ private static final String KEY_ALLOW_IGNORE_ORIENTATION_REQUEST =
+ "allow_ignore_orientation_request";
+
+ private static final boolean DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST = true;
+
+ // Whether sending compat fake focus is enabled for unfocused apps in splitscreen.
+ // Some game engines wait to get focus before drawing the content of the app so
+ // this needs to be used otherwise the apps get blacked out when they are resumed
+ // and do not have focus yet.
+ private static final String KEY_ENABLE_COMPAT_FAKE_FOCUS = "enable_compat_fake_focus";
+
+ private static final boolean DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS = true;
+
+ // Whether translucent activities policy is enabled
+ private static final String KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY =
+ "enable_letterbox_translucent_activity";
+
+ private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY = true;
+
+ // Whether per-app user aspect ratio override settings is enabled
+ private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
+ "enable_app_compat_user_aspect_ratio_settings";
+
+ // TODO(b/288142656): Enable user aspect ratio settings by default.
+ private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+
/**
* Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
* set-fixed-orientation-letterbox-aspect-ratio or via {@link
@@ -52,6 +93,9 @@
*/
static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
+ /** The default aspect ratio for a letterboxed app in multi-window mode. */
+ static final float DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW = 1.01f;
+
/** Letterboxed app window position multiplier indicating center position. */
static final float LETTERBOX_POSITION_MULTIPLIER_CENTER = 0.5f;
@@ -202,26 +246,16 @@
// unresizable apps
private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox;
- // Whether letterboxing strategy is enabled for translucent activities. If {@value false}
- // all the feature is disabled
- private boolean mTranslucentLetterboxingEnabled;
-
// Allows to enable letterboxing strategy for translucent activities ignoring flags.
private boolean mTranslucentLetterboxingOverrideEnabled;
- // Whether sending compat fake focus is enabled for unfocused apps in splitscreen. Some game
- // engines wait to get focus before drawing the content of the app so this needs to be used
- // otherwise the apps get blacked out when they are resumed and do not have focus yet.
- private boolean mIsCompatFakeFocusEnabled;
+ // Allows to enable user aspect ratio settings ignoring flags.
+ private boolean mUserAppAspectRatioSettingsOverrideEnabled;
// Whether we should use split screen aspect ratio for the activity when camera compat treatment
// is enabled and activity is connected to the camera in fullscreen.
private final boolean mIsCameraCompatSplitScreenAspectRatioEnabled;
- // Whether camera compatibility treatment is enabled.
- // See DisplayRotationCompatPolicy for context.
- private final boolean mIsCameraCompatTreatmentEnabled;
-
// Whether activity "refresh" in camera compatibility treatment is enabled.
// See RefreshCallbackItem for context.
private boolean mIsCameraCompatTreatmentRefreshEnabled = true;
@@ -237,15 +271,8 @@
// LetterboxUiController#shouldIgnoreRequestedOrientation for details.
private final boolean mIsPolicyForIgnoringRequestedOrientationEnabled;
- // Whether enabling rotation compat policy for immersive apps that prevents auto rotation
- // into non-optimal screen orientation while in fullscreen. This is needed because immersive
- // apps, such as games, are often not optimized for all orientations and can have a poor UX
- // when rotated. Additionally, some games rely on sensors for the gameplay so users can trigger
- // such rotations accidentally when auto rotation is on.
- private final boolean mIsDisplayRotationImmersiveAppCompatPolicyEnabled;
-
// Flags dynamically updated with {@link android.provider.DeviceConfig}.
- @NonNull private final LetterboxConfigurationDeviceConfig mDeviceConfig;
+ @NonNull private final SynchedDeviceConfig mDeviceConfig;
LetterboxConfiguration(@NonNull final Context systemUiContext) {
this(systemUiContext,
@@ -264,7 +291,6 @@
LetterboxConfiguration(@NonNull final Context systemUiContext,
@NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister) {
mContext = systemUiContext;
- mDeviceConfig = new LetterboxConfigurationDeviceConfig(systemUiContext.getMainExecutor());
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
R.dimen.config_fixedOrientationLetterboxAspectRatio);
@@ -302,36 +328,38 @@
mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources()
.getBoolean(R.bool
.config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled);
- mTranslucentLetterboxingEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsEnabledForTranslucentActivities);
- mIsCameraCompatTreatmentEnabled = mContext.getResources().getBoolean(
- R.bool.config_isWindowManagerCameraCompatTreatmentEnabled);
mIsCameraCompatSplitScreenAspectRatioEnabled = mContext.getResources().getBoolean(
R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled);
- mIsCompatFakeFocusEnabled = mContext.getResources().getBoolean(
- R.bool.config_isCompatFakeFocusEnabled);
mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled);
- mIsDisplayRotationImmersiveAppCompatPolicyEnabled = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsDisplayRotationImmersiveAppCompatPolicyEnabled);
- mDeviceConfig.updateFlagActiveStatus(
- /* isActive */ mIsCameraCompatTreatmentEnabled,
- /* key */ KEY_ENABLE_CAMERA_COMPAT_TREATMENT);
- mDeviceConfig.updateFlagActiveStatus(
- /* isActive */ mIsDisplayRotationImmersiveAppCompatPolicyEnabled,
- /* key */ KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY);
- mDeviceConfig.updateFlagActiveStatus(
- /* isActive */ true,
- /* key */ KEY_ALLOW_IGNORE_ORIENTATION_REQUEST);
- mDeviceConfig.updateFlagActiveStatus(
- /* isActive */ mIsCompatFakeFocusEnabled,
- /* key */ KEY_ENABLE_COMPAT_FAKE_FOCUS);
- mDeviceConfig.updateFlagActiveStatus(
- /* isActive */ mTranslucentLetterboxingEnabled,
- /* key */ KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY);
mLetterboxConfigurationPersister = letterboxConfigurationPersister;
mLetterboxConfigurationPersister.start();
+
+ mDeviceConfig = SynchedDeviceConfig.builder(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ systemUiContext.getMainExecutor())
+ .addDeviceConfigEntry(KEY_ENABLE_CAMERA_COMPAT_TREATMENT,
+ DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT,
+ mContext.getResources().getBoolean(
+ R.bool.config_isWindowManagerCameraCompatTreatmentEnabled))
+ .addDeviceConfigEntry(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
+ DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
+ mContext.getResources().getBoolean(R.bool
+ .config_letterboxIsDisplayRotationImmersiveAppCompatPolicyEnabled))
+ .addDeviceConfigEntry(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST,
+ DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST, /* enabled */ true)
+ .addDeviceConfigEntry(KEY_ENABLE_COMPAT_FAKE_FOCUS,
+ DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS,
+ mContext.getResources().getBoolean(R.bool.config_isCompatFakeFocusEnabled))
+ .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY,
+ DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY,
+ mContext.getResources().getBoolean(
+ R.bool.config_letterboxIsEnabledForTranslucentActivities))
+ .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS,
+ DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS,
+ mContext.getResources().getBoolean(
+ R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled))
+ .build();
}
/**
@@ -339,7 +367,7 @@
* via {@link android.provider.DeviceConfig}.
*/
boolean isIgnoreOrientationRequestAllowed() {
- return mDeviceConfig.getFlag(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST);
+ return mDeviceConfig.getFlagValue(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST);
}
/**
@@ -1046,28 +1074,21 @@
}
boolean isTranslucentLetterboxingEnabled() {
- return mTranslucentLetterboxingOverrideEnabled || (mTranslucentLetterboxingEnabled
- && mDeviceConfig.getFlag(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY));
- }
-
- void setTranslucentLetterboxingEnabled(boolean translucentLetterboxingEnabled) {
- mTranslucentLetterboxingEnabled = translucentLetterboxingEnabled;
+ return mTranslucentLetterboxingOverrideEnabled
+ || mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY);
}
void setTranslucentLetterboxingOverrideEnabled(
boolean translucentLetterboxingOverrideEnabled) {
mTranslucentLetterboxingOverrideEnabled = translucentLetterboxingOverrideEnabled;
- setTranslucentLetterboxingEnabled(translucentLetterboxingOverrideEnabled);
}
/**
* Resets whether we use the constraints override strategy for letterboxing when dealing
- * with translucent activities {@link R.bool.config_letterboxIsEnabledForTranslucentActivities}.
+ * with translucent activities
+ * {@link mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY)}.
*/
void resetTranslucentLetterboxingEnabled() {
- final boolean newValue = mContext.getResources().getBoolean(
- R.bool.config_letterboxIsEnabledForTranslucentActivities);
- setTranslucentLetterboxingEnabled(newValue);
setTranslucentLetterboxingOverrideEnabled(false);
}
@@ -1097,15 +1118,7 @@
/** Whether fake sending focus is enabled for unfocused apps in splitscreen */
boolean isCompatFakeFocusEnabled() {
- return mIsCompatFakeFocusEnabled && mDeviceConfig.getFlag(KEY_ENABLE_COMPAT_FAKE_FOCUS);
- }
-
- /**
- * Overrides whether fake sending focus is enabled for unfocused apps in splitscreen
- */
- @VisibleForTesting
- void setIsCompatFakeFocusEnabled(boolean enabled) {
- mIsCompatFakeFocusEnabled = enabled;
+ return mDeviceConfig.getFlagValue(KEY_ENABLE_COMPAT_FAKE_FOCUS);
}
/**
@@ -1125,10 +1138,20 @@
return mIsCameraCompatSplitScreenAspectRatioEnabled;
}
- /** Whether camera compatibility treatment is enabled. */
- boolean isCameraCompatTreatmentEnabled(boolean checkDeviceConfig) {
- return mIsCameraCompatTreatmentEnabled && (!checkDeviceConfig
- || mDeviceConfig.getFlag(KEY_ENABLE_CAMERA_COMPAT_TREATMENT));
+ /**
+ * @return Whether camera compatibility treatment is currently enabled.
+ */
+ boolean isCameraCompatTreatmentEnabled() {
+ return mDeviceConfig.getFlagValue(KEY_ENABLE_CAMERA_COMPAT_TREATMENT);
+ }
+
+ /**
+ * @return Whether camera compatibility treatment is enabled at build time. This is used when
+ * we need to safely initialize a component before the {@link DeviceConfig} flag value is
+ * available.
+ */
+ boolean isCameraCompatTreatmentEnabledAtBuildTime() {
+ return mDeviceConfig.isBuildTimeFlagEnabled(KEY_ENABLE_CAMERA_COMPAT_TREATMENT);
}
/** Whether camera compatibility refresh is enabled. */
@@ -1174,18 +1197,48 @@
/**
* Checks whether rotation compat policy for immersive apps that prevents auto rotation
- * into non-optimal screen orientation while in fullscreen is enabled.
+ * into non-optimal screen orientation while in fullscreen is enabled at build time. This is
+ * used when we need to safely initialize a component before the {@link DeviceConfig} flag
+ * value is available.
*
* <p>This is needed because immersive apps, such as games, are often not optimized for all
* orientations and can have a poor UX when rotated. Additionally, some games rely on sensors
* for the gameplay so users can trigger such rotations accidentally when auto rotation is on.
- *
- * @param checkDeviceConfig whether should check both static config and a dynamic property
- * from {@link DeviceConfig} or only static value.
*/
- boolean isDisplayRotationImmersiveAppCompatPolicyEnabled(final boolean checkDeviceConfig) {
- return mIsDisplayRotationImmersiveAppCompatPolicyEnabled && (!checkDeviceConfig
- || mDeviceConfig.getFlag(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY));
+ boolean isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime() {
+ return mDeviceConfig.isBuildTimeFlagEnabled(
+ KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY);
}
+ /**
+ * Checks whether rotation compat policy for immersive apps that prevents auto rotation
+ * into non-optimal screen orientation while in fullscreen is currently enabled.
+ *
+ * <p>This is needed because immersive apps, such as games, are often not optimized for all
+ * orientations and can have a poor UX when rotated. Additionally, some games rely on sensors
+ * for the gameplay so users can trigger such rotations accidentally when auto rotation is on.
+ */
+ boolean isDisplayRotationImmersiveAppCompatPolicyEnabled() {
+ return mDeviceConfig.getFlagValue(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY);
+ }
+
+ /**
+ * Whether per-app user aspect ratio override settings is enabled
+ */
+ boolean isUserAppAspectRatioSettingsEnabled() {
+ return mUserAppAspectRatioSettingsOverrideEnabled
+ || mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS);
+ }
+
+ void setUserAppAspectRatioSettingsOverrideEnabled(boolean enabled) {
+ mUserAppAspectRatioSettingsOverrideEnabled = enabled;
+ }
+
+ /**
+ * Resets whether per-app user aspect ratio override settings is enabled
+ * {@code mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS)}.
+ */
+ void resetUserAppAspectRatioSettingsEnabled() {
+ setUserAppAspectRatioSettingsOverrideEnabled(false);
+ }
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java b/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java
deleted file mode 100644
index a739e42..0000000
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.provider.DeviceConfig;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * Utility class that caches {@link DeviceConfig} flags for app compat features and listens
- * to updates by implementing {@link DeviceConfig.OnPropertiesChangedListener}.
- */
-final class LetterboxConfigurationDeviceConfig
- implements DeviceConfig.OnPropertiesChangedListener {
-
- static final String KEY_ENABLE_CAMERA_COMPAT_TREATMENT = "enable_compat_camera_treatment";
- private static final boolean DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT = true;
-
- static final String KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
- "enable_display_rotation_immersive_app_compat_policy";
- private static final boolean DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
- true;
-
- static final String KEY_ALLOW_IGNORE_ORIENTATION_REQUEST =
- "allow_ignore_orientation_request";
- private static final boolean DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST = true;
-
- static final String KEY_ENABLE_COMPAT_FAKE_FOCUS = "enable_compat_fake_focus";
- private static final boolean DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS = true;
-
- static final String KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY =
- "enable_letterbox_translucent_activity";
-
- private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY = true;
-
- @VisibleForTesting
- static final Map<String, Boolean> sKeyToDefaultValueMap = Map.of(
- KEY_ENABLE_CAMERA_COMPAT_TREATMENT,
- DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT,
- KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
- DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
- KEY_ALLOW_IGNORE_ORIENTATION_REQUEST,
- DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST,
- KEY_ENABLE_COMPAT_FAKE_FOCUS,
- DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS,
- KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY,
- DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY
- );
-
- // Whether camera compatibility treatment is enabled.
- // See DisplayRotationCompatPolicy for context.
- private boolean mIsCameraCompatTreatmentEnabled =
- DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT;
-
- // Whether enabling rotation compat policy for immersive apps that prevents auto rotation
- // into non-optimal screen orientation while in fullscreen. This is needed because immersive
- // apps, such as games, are often not optimized for all orientations and can have a poor UX
- // when rotated. Additionally, some games rely on sensors for the gameplay so users can trigger
- // such rotations accidentally when auto rotation is on.
- private boolean mIsDisplayRotationImmersiveAppCompatPolicyEnabled =
- DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY;
-
- // Whether enabling ignoreOrientationRequest is allowed on the device.
- private boolean mIsAllowIgnoreOrientationRequest =
- DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST;
-
- // Whether sending compat fake focus for split screen resumed activities is enabled. This is
- // needed because some game engines wait to get focus before drawing the content of the app
- // which isn't guaranteed by default in multi-window modes.
- private boolean mIsCompatFakeFocusAllowed = DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS;
-
- // Whether the letterbox strategy for transparent activities is allowed
- private boolean mIsTranslucentLetterboxingAllowed =
- DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY;
-
- // Set of active device configs that need to be updated in
- // DeviceConfig.OnPropertiesChangedListener#onPropertiesChanged.
- private final ArraySet<String> mActiveDeviceConfigsSet = new ArraySet<>();
-
- LetterboxConfigurationDeviceConfig(@NonNull final Executor executor) {
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- executor, /* onPropertiesChangedListener */ this);
- }
-
- @Override
- public void onPropertiesChanged(@NonNull final DeviceConfig.Properties properties) {
- for (int i = mActiveDeviceConfigsSet.size() - 1; i >= 0; i--) {
- String key = mActiveDeviceConfigsSet.valueAt(i);
- // Reads the new configuration, if the device config properties contain the key.
- if (properties.getKeyset().contains(key)) {
- readAndSaveValueFromDeviceConfig(key);
- }
- }
- }
-
- /**
- * Adds {@code key} to a set of flags that can be updated from the server if
- * {@code isActive} is {@code true} and read it's current value from {@link DeviceConfig}.
- */
- void updateFlagActiveStatus(boolean isActive, String key) {
- if (!isActive) {
- return;
- }
- mActiveDeviceConfigsSet.add(key);
- readAndSaveValueFromDeviceConfig(key);
- }
-
- /**
- * Returns values of the {@code key} flag.
- *
- * @throws AssertionError {@code key} isn't recognised.
- */
- boolean getFlag(String key) {
- switch (key) {
- case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
- return mIsCameraCompatTreatmentEnabled;
- case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
- return mIsDisplayRotationImmersiveAppCompatPolicyEnabled;
- case KEY_ALLOW_IGNORE_ORIENTATION_REQUEST:
- return mIsAllowIgnoreOrientationRequest;
- case KEY_ENABLE_COMPAT_FAKE_FOCUS:
- return mIsCompatFakeFocusAllowed;
- case KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY:
- return mIsTranslucentLetterboxingAllowed;
- default:
- throw new AssertionError("Unexpected flag name: " + key);
- }
- }
-
- private void readAndSaveValueFromDeviceConfig(String key) {
- Boolean defaultValue = sKeyToDefaultValueMap.get(key);
- if (defaultValue == null) {
- throw new AssertionError("Haven't found default value for flag: " + key);
- }
- switch (key) {
- case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
- mIsCameraCompatTreatmentEnabled = getDeviceConfig(key, defaultValue);
- break;
- case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
- mIsDisplayRotationImmersiveAppCompatPolicyEnabled =
- getDeviceConfig(key, defaultValue);
- break;
- case KEY_ALLOW_IGNORE_ORIENTATION_REQUEST:
- mIsAllowIgnoreOrientationRequest = getDeviceConfig(key, defaultValue);
- break;
- case KEY_ENABLE_COMPAT_FAKE_FOCUS:
- mIsCompatFakeFocusAllowed = getDeviceConfig(key, defaultValue);
- break;
- case KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY:
- mIsTranslucentLetterboxingAllowed = getDeviceConfig(key, defaultValue);
- break;
- default:
- throw new AssertionError("Unexpected flag name: " + key);
- }
- }
-
- private boolean getDeviceConfig(String key, boolean defaultValue) {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- key, defaultValue);
- }
-}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
index 3b10deb..7563397 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.os.StrictMode.setThreadPolicy;
+
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -23,6 +25,8 @@
import android.annotation.Nullable;
import android.content.Context;
import android.os.Environment;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
import android.util.AtomicFile;
import android.util.Slog;
@@ -125,7 +129,7 @@
final File prefFiles = new File(configFolder, LETTERBOX_CONFIGURATION_FILENAME);
mConfigurationFile = new AtomicFile(prefFiles);
mPersisterQueue = persisterQueue;
- readCurrentConfiguration();
+ runWithDiskReadsThreadPolicy(this::readCurrentConfiguration);
}
/**
@@ -275,6 +279,20 @@
}
}
+ // The LetterboxConfigurationDeviceConfig needs to access the
+ // file with the current reachability position once when the
+ // device boots. Because DisplayThread uses allowIo=false
+ // accessing a file triggers a DiskReadViolation.
+ // Here we use StrictMode to allow the current thread to read
+ // the AtomicFile once in the current thread restoring the
+ // original ThreadPolicy after that.
+ private void runWithDiskReadsThreadPolicy(Runnable runnable) {
+ final ThreadPolicy currentPolicy = StrictMode.getThreadPolicy();
+ setThreadPolicy(new ThreadPolicy.Builder().permitDiskReads().build());
+ runnable.run();
+ setThreadPolicy(currentPolicy);
+ }
+
private static class UpdateValuesCommand implements
PersisterQueue.WriteQueueItem<UpdateValuesCommand> {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index c243988..a816838 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -294,18 +294,15 @@
PROPERTY_COMPAT_ENABLE_FAKE_FOCUS);
mBooleanPropertyCameraCompatAllowForceRotation =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ true),
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
mBooleanPropertyCameraCompatAllowRefresh =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ true),
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
mBooleanPropertyCameraCompatEnableRefreshViaPause =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ true),
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
mBooleanPropertyAllowOrientationOverride =
@@ -697,7 +694,7 @@
boolean shouldRefreshActivityForCameraCompat() {
return shouldEnableWithOptOutOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ .isCameraCompatTreatmentEnabled(),
mIsOverrideCameraCompatDisableRefreshEnabled,
mBooleanPropertyCameraCompatAllowRefresh);
}
@@ -719,7 +716,7 @@
boolean shouldRefreshActivityViaPauseForCameraCompat() {
return shouldEnableWithOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ .isCameraCompatTreatmentEnabled(),
mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
mBooleanPropertyCameraCompatEnableRefreshViaPause);
}
@@ -738,7 +735,7 @@
boolean shouldForceRotateForCameraCompat() {
return shouldEnableWithOptOutOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ .isCameraCompatTreatmentEnabled(),
mIsOverrideCameraCompatDisableForceRotationEnabled,
mBooleanPropertyCameraCompatAllowForceRotation);
}
diff --git a/services/core/java/com/android/server/wm/SynchedDeviceConfig.java b/services/core/java/com/android/server/wm/SynchedDeviceConfig.java
new file mode 100644
index 0000000..c2e819e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SynchedDeviceConfig.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.provider.DeviceConfig;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * Utility class that caches {@link DeviceConfig} flags and listens to updates by implementing
+ * {@link DeviceConfig.OnPropertiesChangedListener}.
+ */
+final class SynchedDeviceConfig implements DeviceConfig.OnPropertiesChangedListener {
+
+ private final String mNamespace;
+ private final Executor mExecutor;
+
+ private final Map<String, SynchedDeviceConfigEntry> mDeviceConfigEntries;
+
+ /**
+ * @param namespace The namespace for the {@link DeviceConfig}
+ * @param executor The {@link Executor} implementation to use when receiving updates
+ * @return the Builder implementation for the SynchedDeviceConfig
+ */
+ @NonNull
+ static SynchedDeviceConfigBuilder builder(@NonNull String namespace,
+ @NonNull Executor executor) {
+ return new SynchedDeviceConfigBuilder(namespace, executor);
+ }
+
+ private SynchedDeviceConfig(@NonNull String namespace, @NonNull Executor executor,
+ @NonNull Map<String, SynchedDeviceConfigEntry> deviceConfigEntries) {
+ mNamespace = namespace;
+ mExecutor = executor;
+ mDeviceConfigEntries = deviceConfigEntries;
+ }
+
+ @Override
+ public void onPropertiesChanged(@NonNull final DeviceConfig.Properties properties) {
+ for (SynchedDeviceConfigEntry entry : mDeviceConfigEntries.values()) {
+ if (properties.getKeyset().contains(entry.mFlagKey)) {
+ entry.updateValue(properties.getBoolean(entry.mFlagKey, entry.mDefaultValue));
+ }
+ }
+ }
+
+ /**
+ * Builds the {@link SynchedDeviceConfig} and start listening to the {@link DeviceConfig}
+ * updates.
+ *
+ * @return The {@link SynchedDeviceConfig}
+ */
+ @NonNull
+ private SynchedDeviceConfig start() {
+ DeviceConfig.addOnPropertiesChangedListener(mNamespace,
+ mExecutor, /* onPropertiesChangedListener */ this);
+ return this;
+ }
+
+ /**
+ * Requests a {@link DeviceConfig} update for all the flags
+ */
+ @NonNull
+ private SynchedDeviceConfig updateFlags() {
+ mDeviceConfigEntries.forEach((key, entry) -> entry.updateValue(
+ isDeviceConfigFlagEnabled(key, entry.mDefaultValue)));
+ return this;
+ }
+
+ /**
+ * Returns values of the {@code key} flag with the following criteria:
+ *
+ * <ul>
+ * <li>{@code false} if the build time flag is disabled.
+ * <li>{@code defaultValue} if the build time flag is enabled and no {@link DeviceConfig}
+ * updates happened
+ * <li>Last value from {@link DeviceConfig} in case of updates.
+ * </ul>
+ *
+ * @throws IllegalArgumentException {@code key} isn't recognised.
+ */
+ boolean getFlagValue(@NonNull String key) {
+ return findEntry(key).map(SynchedDeviceConfigEntry::getValue)
+ .orElseThrow(() -> new IllegalArgumentException("Unexpected flag name: " + key));
+ }
+
+ /**
+ * @return {@code true} if the flag for the given {@code key} was enabled at build time.
+ */
+ boolean isBuildTimeFlagEnabled(@NonNull String key) {
+ return findEntry(key).map(SynchedDeviceConfigEntry::isBuildTimeFlagEnabled)
+ .orElseThrow(() -> new IllegalArgumentException("Unexpected flag name: " + key));
+ }
+
+ private boolean isDeviceConfigFlagEnabled(@NonNull String key, boolean defaultValue) {
+ return DeviceConfig.getBoolean(mNamespace, key, defaultValue);
+ }
+
+ @NonNull
+ private Optional<SynchedDeviceConfigEntry> findEntry(@NonNull String key) {
+ return Optional.ofNullable(mDeviceConfigEntries.get(key));
+ }
+
+ static class SynchedDeviceConfigBuilder {
+
+ private final String mNamespace;
+ private final Executor mExecutor;
+
+ private final Map<String, SynchedDeviceConfigEntry> mDeviceConfigEntries =
+ new ConcurrentHashMap<>();
+
+ private SynchedDeviceConfigBuilder(@NonNull String namespace, @NonNull Executor executor) {
+ mNamespace = namespace;
+ mExecutor = executor;
+ }
+
+ @NonNull
+ SynchedDeviceConfigBuilder addDeviceConfigEntry(@NonNull String key,
+ boolean defaultValue, boolean enabled) {
+ if (mDeviceConfigEntries.containsKey(key)) {
+ throw new AssertionError("Key already present: " + key);
+ }
+ mDeviceConfigEntries.put(key,
+ new SynchedDeviceConfigEntry(key, defaultValue, enabled));
+ return this;
+ }
+
+ @NonNull
+ SynchedDeviceConfig build() {
+ return new SynchedDeviceConfig(mNamespace, mExecutor,
+ mDeviceConfigEntries).updateFlags().start();
+ }
+ }
+
+ /**
+ * Contains all the information related to an entry to be managed by DeviceConfig
+ */
+ private static class SynchedDeviceConfigEntry {
+
+ // The key of the specific configuration flag
+ private final String mFlagKey;
+
+ // The value of the flag at build time.
+ private final boolean mBuildTimeFlagEnabled;
+
+ // The initial value of the flag when mBuildTimeFlagEnabled is true.
+ private final boolean mDefaultValue;
+
+ // The current value of the flag when mBuildTimeFlagEnabled is true.
+ private volatile boolean mOverrideValue;
+
+ private SynchedDeviceConfigEntry(@NonNull String flagKey, boolean defaultValue,
+ boolean enabled) {
+ mFlagKey = flagKey;
+ mOverrideValue = mDefaultValue = defaultValue;
+ mBuildTimeFlagEnabled = enabled;
+ }
+
+ @NonNull
+ private void updateValue(boolean newValue) {
+ mOverrideValue = newValue;
+ }
+
+ private boolean getValue() {
+ return mBuildTimeFlagEnabled && mOverrideValue;
+ }
+
+ private boolean isBuildTimeFlagEnabled() {
+ return mBuildTimeFlagEnabled;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index aad1225..0059f0b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -358,22 +358,30 @@
mTransientLaunches.put(activity, restoreBelow);
setTransientLaunchToChanges(activity);
- if (restoreBelow != null) {
- final Task transientRootTask = activity.getRootTask();
+ final Task transientRootTask = activity.getRootTask();
+ final WindowContainer<?> parent = restoreBelow != null ? restoreBelow.getParent()
+ : (transientRootTask != null ? transientRootTask.getParent() : null);
+ if (parent != null) {
// Collect all visible tasks which can be occluded by the transient activity to
// make sure they are in the participants so their visibilities can be updated when
// finishing transition.
- ((WindowContainer<?>) restoreBelow.getParent()).forAllTasks(t -> {
+ parent.forAllTasks(t -> {
+ // Skip transient-launch task
+ if (t == transientRootTask) return false;
if (t.isVisibleRequested() && !t.isAlwaysOnTop()
&& !t.getWindowConfiguration().tasksAreFloating()) {
- if (t.isRootTask() && t != transientRootTask) {
+ if (t.isRootTask()) {
mTransientHideTasks.add(t);
}
if (t.isLeafTask()) {
collect(t);
}
}
- return t == restoreBelow;
+ return restoreBelow != null
+ // Stop at the restoreBelow task
+ ? t == restoreBelow
+ // Or stop at the last visible task if no restore-below (new task)
+ : (t.isRootTask() && t.fillsParent());
});
// Add FLAG_ABOVE_TRANSIENT_LAUNCH to the tree of transient-hide tasks,
// so ChangeInfo#hasChanged() can return true to report the transition info.
@@ -397,6 +405,28 @@
return false;
}
+ boolean canApplyDim(@NonNull Task task) {
+ if (mTransientLaunches == null) return true;
+ final Dimmer dimmer = task.getDimmer();
+ final WindowContainer<?> dimmerHost = dimmer != null ? dimmer.getHost() : null;
+ if (dimmerHost == null) return false;
+ if (isInTransientHide(dimmerHost)) {
+ // The layer of dimmer is inside transient-hide task, then allow to dim.
+ return true;
+ }
+ // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
+ for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+ // The transient task is usually the task of recents/home activity.
+ final Task transientTask = mTransientLaunches.keyAt(i).getTask();
+ if (transientTask != null && transientTask.canAffectSystemUiFlags()) {
+ // It usually means that the recents animation has moved the transient-hide task
+ // an noticeable distance, then the display level dimmer should not show.
+ return false;
+ }
+ }
+ return true;
+ }
+
boolean hasTransientLaunch() {
return mTransientLaunches != null && !mTransientLaunches.isEmpty();
}
@@ -957,7 +987,7 @@
}
if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
- if (didCommitTransientLaunch()) {
+ if (!ar.getTask().isVisibleRequested() || didCommitTransientLaunch()) {
// force enable pip-on-task-switch now that we've committed to actually launching
// to the transient activity.
ar.supportsEnterPipOnTaskSwitch = true;
@@ -986,7 +1016,8 @@
}
// Legacy pip-entry (not via isAutoEnterEnabled).
- if (didCommitTransientLaunch() && ar.supportsPictureInPicture()) {
+ if ((!ar.getTask().isVisibleRequested() || didCommitTransientLaunch())
+ && ar.supportsPictureInPicture()) {
// force enable pip-on-task-switch now that we've committed to actually launching to the
// transient activity, and then recalculate whether we can attempt pip.
ar.supportsEnterPipOnTaskSwitch = true;
@@ -1224,6 +1255,16 @@
mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
}
+ if (mTransientLaunches != null) {
+ for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+ // Reset the ability of controlling SystemUi which might be changed by
+ // setTransientLaunch or setRecentsAppBehindSystemBars.
+ final Task task = mTransientLaunches.keyAt(i).getTask();
+ if (task != null) {
+ task.setCanAffectSystemUiFlags(true);
+ }
+ }
+ }
for (int i = 0; i < mTargetDisplays.size(); ++i) {
final DisplayContent dc = mTargetDisplays.get(i);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 359b353..a539a48 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -58,6 +58,7 @@
import com.android.server.FgThread;
import java.util.ArrayList;
+import java.util.function.Consumer;
import java.util.function.LongConsumer;
/**
@@ -476,6 +477,19 @@
return false;
}
+ boolean canApplyDim(@Nullable Task task) {
+ if (task == null) {
+ // Always allow non-activity window.
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (!mPlayingTransitions.get(i).canApplyDim(task)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* During transient-launch, the "behind" app should retain focus during the transition unless
* something takes focus from it explicitly (eg. by calling ATMS.setFocusedTask or by another
@@ -1314,18 +1328,18 @@
return transit;
}
- /** Returns {@code true} if it started collecting, {@code false} if it was queued. */
- boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) {
+ /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */
+ void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) {
if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) {
// Just add to queue since we already have a queue.
- mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run()));
+ mQueuedTransitions.add(new QueuedTransition(syncGroup,
+ (deferred) -> applySync.accept(true /* deferred */)));
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
"Queueing legacy sync-set: %s", syncGroup.mSyncId);
- return false;
+ return;
}
mSyncEngine.startSyncSet(syncGroup);
- applySync.run();
- return true;
+ applySync.accept(false /* deferred */);
}
interface OnStartCollect {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index f54a962..0cf4e89 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -137,7 +136,8 @@
};
private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
- if (!w.mTransitionController.isShellTransitionsEnabled()) {
+ final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled();
+ if (!useShellTransition) {
if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
&& !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
// If this window's app token is hidden and not animating, it is of no interest.
@@ -159,30 +159,23 @@
final WindowContainer animatingContainer = w.mActivityRecord != null
? w.mActivityRecord.getAnimatingContainer() : null;
- final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
+ if (!useShellTransition && animatingContainer != null
&& animatingContainer.isAnimating(TRANSITION | PARENTS)
&& AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
&& (animatingContainer.mTransitFlags
- & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
-
- boolean needsShowWhenLockedWallpaper = false;
- if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked()) {
- final TransitionController tc = w.mTransitionController;
- final boolean isInTransition = tc.isShellTransitionsEnabled()
- && tc.inTransition(w);
- if (mService.mPolicy.isKeyguardOccluded() || mService.mPolicy.isKeyguardUnoccluding()
- || isInTransition) {
- // The lowest show when locked window decides whether we need to put the wallpaper
- // behind.
- needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
- || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
- }
+ & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) {
+ // Keep the wallpaper visible when Keyguard is going away.
+ mFindResults.setUseTopWallpaperAsTarget(true);
}
- if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
- // Keep the wallpaper during Keyguard exit but also when it's needed for a
- // non-fullscreen show when locked activity.
- mFindResults.setUseTopWallpaperAsTarget(true);
+ if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) {
+ if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
+ ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
+ // The lowest show when locked window decides whether we need to put the wallpaper
+ // behind.
+ mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
+ || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
+ }
}
final boolean animationWallpaper = animatingContainer != null
@@ -691,7 +684,8 @@
private void findWallpaperTarget() {
mFindResults.reset();
- if (mDisplayContent.getDefaultTaskDisplayArea()
+ if (mService.mAtmService.mSupportsFreeformWindowManagement
+ && mDisplayContent.getDefaultTaskDisplayArea()
.isRootTaskVisible(WINDOWING_MODE_FREEFORM)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
@@ -700,6 +694,10 @@
mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */);
mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
+ if (mFindResults.mNeedsShowWhenLockedWallpaper) {
+ // Keep wallpaper visible if the show-when-locked activities doesn't fill screen.
+ mFindResults.setUseTopWallpaperAsTarget(true);
+ }
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
mFindResults.setWallpaperTarget(
@@ -1084,6 +1082,7 @@
}
TopWallpaper mTopWallpaper = new TopWallpaper();
+ boolean mNeedsShowWhenLockedWallpaper;
boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
boolean isWallpaperTargetForLetterbox = false;
@@ -1132,6 +1131,7 @@
void reset() {
mTopWallpaper.reset();
+ mNeedsShowWhenLockedWallpaper = false;
wallpaperTarget = null;
useTopWallpaperAsTarget = false;
isWallpaperTargetForLetterbox = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a153708..05e858d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -1006,13 +1006,16 @@
runSetBooleanFlag(pw, mLetterboxConfiguration
::setTranslucentLetterboxingOverrideEnabled);
break;
+ case "--isUserAppAspectRatioSettingsEnabled":
+ runSetBooleanFlag(pw, mLetterboxConfiguration
+ ::setUserAppAspectRatioSettingsOverrideEnabled);
+ break;
case "--isCameraCompatRefreshEnabled":
- runSetBooleanFlag(pw, enabled -> mLetterboxConfiguration
- .setCameraCompatRefreshEnabled(enabled));
+ runSetBooleanFlag(pw, mLetterboxConfiguration::setCameraCompatRefreshEnabled);
break;
case "--isCameraCompatRefreshCycleThroughStopEnabled":
- runSetBooleanFlag(pw, enabled -> mLetterboxConfiguration
- .setCameraCompatRefreshCycleThroughStopEnabled(enabled));
+ runSetBooleanFlag(pw,
+ mLetterboxConfiguration::setCameraCompatRefreshCycleThroughStopEnabled);
break;
default:
getErrPrintWriter().println(
@@ -1084,6 +1087,9 @@
case "isTranslucentLetterboxingEnabled":
mLetterboxConfiguration.resetTranslucentLetterboxingEnabled();
break;
+ case "isUserAppAspectRatioSettingsEnabled":
+ mLetterboxConfiguration.resetUserAppAspectRatioSettingsEnabled();
+ break;
case "isCameraCompatRefreshEnabled":
mLetterboxConfiguration.resetCameraCompatRefreshEnabled();
break;
@@ -1194,6 +1200,7 @@
mLetterboxConfiguration.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
mLetterboxConfiguration.resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
mLetterboxConfiguration.resetTranslucentLetterboxingEnabled();
+ mLetterboxConfiguration.resetUserAppAspectRatioSettingsEnabled();
mLetterboxConfiguration.resetCameraCompatRefreshEnabled();
mLetterboxConfiguration.resetCameraCompatRefreshCycleThroughStopEnabled();
}
@@ -1249,7 +1256,6 @@
+ mLetterboxConfiguration.isCameraCompatRefreshEnabled());
pw.println(" Refresh using \"stopped -> resumed\" cycle: "
+ mLetterboxConfiguration.isCameraCompatRefreshCycleThroughStopEnabled());
-
pw.println("Background type: "
+ LetterboxConfiguration.letterboxBackgroundTypeToString(
mLetterboxConfiguration.getLetterboxBackgroundType()));
@@ -1259,12 +1265,10 @@
+ mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius());
pw.println(" Wallpaper dark scrim alpha: "
+ mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha());
-
- if (mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) {
- pw.println("Letterboxing for translucent activities: enabled");
- } else {
- pw.println("Letterboxing for translucent activities: disabled");
- }
+ pw.println("Is letterboxing for translucent activities enabled: "
+ + mLetterboxConfiguration.isTranslucentLetterboxingEnabled());
+ pw.println("Is the user aspect ratio settings enabled: "
+ + mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled());
}
return 0;
}
@@ -1462,6 +1466,8 @@
pw.println(" unresizable apps.");
pw.println(" --isTranslucentLetterboxingEnabled [true|1|false|0]");
pw.println(" Whether letterboxing for translucent activities is enabled.");
+ pw.println(" --isUserAppAspectRatioSettingsEnabled [true|1|false|0]");
+ pw.println(" Whether user aspect ratio settings are enabled.");
pw.println(" --isCameraCompatRefreshEnabled [true|1|false|0]");
pw.println(" Whether camera compatibility refresh is enabled.");
pw.println(" --isCameraCompatRefreshCycleThroughStopEnabled [true|1|false|0]");
@@ -1473,7 +1479,7 @@
pw.println(" |horizontalPositionMultiplier|verticalPositionMultiplier");
pw.println(" |isHorizontalReachabilityEnabled|isVerticalReachabilityEnabled");
pw.println(" |isEducationEnabled||defaultPositionMultiplierForHorizontalReachability");
- pw.println(" |isTranslucentLetterboxingEnabled");
+ pw.println(" |isTranslucentLetterboxingEnabled|isUserAppAspectRatioSettingsEnabled");
pw.println(" |defaultPositionMultiplierForVerticalReachability]");
pw.println(" Resets overrides to default values for specified properties separated");
pw.println(" by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 811d9b6..7b64fed 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -232,8 +232,8 @@
final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
final int syncId = syncGroup.mSyncId;
if (mTransitionController.isShellTransitionsEnabled()) {
- mTransitionController.startLegacySyncOrQueue(syncGroup, () -> {
- applyTransaction(t, syncId, null /*transition*/, caller);
+ mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> {
+ applyTransaction(t, syncId, null /* transition */, caller, deferred);
setSyncReady(syncId);
});
} else {
@@ -304,7 +304,8 @@
(deferred) -> {
nextTransition.start();
nextTransition.mLogger.mStartWCT = wct;
- applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+ applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
+ deferred);
if (needsSetReady) {
nextTransition.setAllReady();
}
@@ -456,7 +457,7 @@
transition.abort();
return;
}
- if (applyTransaction(wct, -1 /* syncId */, transition, caller)
+ if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred)
== TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
transition.abort();
return;
@@ -476,6 +477,23 @@
return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
}
+ private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
+ @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {
+ if (deferred) {
+ try {
+ return applyTransaction(t, syncId, transition, caller);
+ } catch (RuntimeException e) {
+ // If the transaction is deferred, the caller could be from TransitionController
+ // #tryStartCollectFromQueue that executes on system's worker thread rather than
+ // binder thread. And the operation in the WCT may be outdated that violates the
+ // current state. So catch the exception to avoid crashing the system.
+ Slog.e(TAG, "Failed to execute deferred applyTransaction", e);
+ }
+ return TRANSACT_EFFECTS_NONE;
+ }
+ return applyTransaction(t, syncId, transition, caller);
+ }
+
/**
* @param syncId If non-null, this will be a sync-transaction.
* @param transition A transition to collect changes into.
@@ -838,13 +856,21 @@
switch (type) {
case HIERARCHY_OP_TYPE_REMOVE_TASK: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || wc.asTask() == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to remove invalid task: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
task.remove(true, "Applying remove task Hierarchy Op");
break;
}
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
} else if (task.getTaskDisplayArea() == null) {
@@ -858,7 +884,11 @@
}
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
final boolean clearRoot = hop.getToTop();
if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a1473b1..5579e52 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2987,10 +2987,11 @@
@Override
public boolean canShowWhenLocked() {
- final boolean showBecauseOfActivity =
- mActivityRecord != null && mActivityRecord.canShowWhenLocked();
- final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
- return showBecauseOfActivity || showBecauseOfWindow;
+ if (mActivityRecord != null) {
+ // It will also check if its windows contain FLAG_SHOW_WHEN_LOCKED.
+ return mActivityRecord.canShowWhenLocked();
+ }
+ return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
}
/**
@@ -5123,12 +5124,13 @@
private void applyDims() {
if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
- && isVisibleNow() && !mHidden) {
+ && isVisibleNow() && !mHidden && mTransitionController.canApplyDim(getTask())) {
// Only show the Dimmer when the following is satisfied:
// 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
// 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
// 3. The WS is considered visible according to the isVisible() method
// 4. The WS is not hidden.
+ // 5. The window is not in a transition or is in a transition that allows to dim.
mIsDimming = true;
final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 3ba4170..cb0b9c9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -277,7 +277,7 @@
base::Result<std::unique_ptr<InputChannel>> createInputChannel(const std::string& name);
base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
const std::string& name,
- int32_t pid);
+ gui::Pid pid);
status_t removeInputChannel(const sp<IBinder>& connectionToken);
status_t pilferPointers(const sp<IBinder>& token);
@@ -328,9 +328,9 @@
void notifyConfigurationChanged(nsecs_t when) override;
// ANR-related callbacks -- start
void notifyNoFocusedWindowAnr(const std::shared_ptr<InputApplicationHandle>& handle) override;
- void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid,
+ void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<gui::Pid> pid,
const std::string& reason) override;
- void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) override;
+ void notifyWindowResponsive(const sp<IBinder>& token, std::optional<gui::Pid> pid) override;
// ANR-related callbacks -- end
void notifyInputChannelBroken(const sp<IBinder>& token) override;
void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
@@ -353,7 +353,7 @@
void setPointerCapture(const PointerCaptureRequest& request) override;
void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) override;
+ const std::set<gui::Uid>& uids) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -538,7 +538,7 @@
}
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
- int32_t displayId, const std::string& name, int32_t pid) {
+ int32_t displayId, const std::string& name, gui::Pid pid) {
ATRACE_CALL();
return mInputManager->getDispatcher().createInputMonitor(displayId, name, pid);
}
@@ -882,7 +882,7 @@
}
void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
- std::optional<int32_t> pid,
+ std::optional<gui::Pid> pid,
const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyWindowUnresponsive");
@@ -896,12 +896,12 @@
ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
- pid.value_or(0), pid.has_value(), reasonObj.get());
+ pid.value_or(gui::Pid{0}).val(), pid.has_value(), reasonObj.get());
checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
}
void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token,
- std::optional<int32_t> pid) {
+ std::optional<gui::Pid> pid) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyWindowResponsive");
#endif
@@ -913,7 +913,7 @@
jobject tokenObj = javaObjectForIBinder(env, token);
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowResponsive, tokenObj,
- pid.value_or(0), pid.has_value());
+ pid.value_or(gui::Pid{0}).val(), pid.has_value());
checkAndClearExceptionFromCallback(env, "notifyWindowResponsive");
}
@@ -966,9 +966,9 @@
}
void NativeInputManager::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) {
+ const std::set<gui::Uid>& uids) {
static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
- sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
+ sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
if (!ENABLE_INPUT_DEVICE_USAGE_METRICS) return;
mInputManager->getMetricsCollector().notifyDeviceInteraction(deviceId, timestamp, uids);
@@ -1804,7 +1804,7 @@
std::string name = nameChars.c_str();
base::Result<std::unique_ptr<InputChannel>> inputChannel =
- im->createInputMonitor(displayId, name, pid);
+ im->createInputMonitor(displayId, name, gui::Pid{pid});
if (!inputChannel.ok()) {
std::string message = inputChannel.error().message();
@@ -1849,7 +1849,8 @@
jint pid, jint uid, jboolean hasPermission, jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- return im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode, pid, uid,
+ return im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode, gui::Pid{pid},
+ gui::Uid{static_cast<uid_t>(uid)},
hasPermission, displayId);
}
@@ -1865,7 +1866,7 @@
jint timeoutMillis, jint policyFlags) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- const std::optional<int32_t> targetUid = injectIntoUid ? std::make_optional(uid) : std::nullopt;
+ const auto targetUid = injectIntoUid ? std::make_optional<gui::Uid>(uid) : std::nullopt;
// static_cast is safe because the value was already checked at the Java layer
InputEventInjectionSync mode = static_cast<InputEventInjectionSync>(syncMode);
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index cadee6f..a1199d9 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -21,6 +21,7 @@
import static android.content.Context.CREDENTIAL_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -55,6 +56,7 @@
import android.provider.Settings;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfoFactory;
+import android.service.credentials.PermissionUtils;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
@@ -546,11 +548,16 @@
if (providerSessions.isEmpty()) {
try {
- // TODO: fix
prepareGetCredentialCallback.onResponse(
- new PrepareGetCredentialResponseInternal(
- false, null,
- false, false, null));
+ new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission(
+ mContext,
+ callingPackage,
+ Manifest.permission
+ .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS),
+ /*credentialResultTypes=*/null,
+ /*hasAuthenticationResults=*/false,
+ /*hasRemoteResults=*/false,
+ /*pendingIntent=*/null));
} catch (RemoteException e) {
Slog.e(
TAG,
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index aee4f58..c9e691e 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -28,6 +28,7 @@
import android.credentials.IGetCredentialCallback;
import android.credentials.ui.ProviderData;
import android.credentials.ui.RequestInfo;
+import android.os.Binder;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
@@ -98,8 +99,9 @@
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
- cancelExistingPendingIntent();
+ Binder.withCleanCallingIdentity(()-> {
try {
+ cancelExistingPendingIntent();
mPendingIntent = mCredentialManagerUi.createPendingIntent(
RequestInfo.newGetRequestInfo(
mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
@@ -112,9 +114,9 @@
mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
String exception = GetCredentialException.TYPE_UNKNOWN;
mRequestSessionMetric.collectFrameworkException(exception);
- respondToClientWithErrorAndFinish(
- exception, "Unable to instantiate selector");
- }
+ respondToClientWithErrorAndFinish(exception, "Unable to instantiate selector");
+ }
+ });
}
@Override
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index b0b72bc..46c90b4 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -38,11 +38,13 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -116,7 +118,7 @@
@NonNull String servicePackageName,
@NonNull CredentialOption requestOption) {
super(context, requestOption, session,
- new ComponentName(servicePackageName, servicePackageName),
+ new ComponentName(servicePackageName, UUID.randomUUID().toString()),
userId, null);
mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
mCallingAppInfo = callingAppInfo;
@@ -133,7 +135,7 @@
@NonNull String servicePackageName,
@NonNull CredentialOption requestOption) {
super(context, requestOption, session,
- new ComponentName(servicePackageName, servicePackageName),
+ new ComponentName(servicePackageName, UUID.randomUUID().toString()),
userId, null);
mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
mCallingAppInfo = callingAppInfo;
@@ -179,7 +181,9 @@
return null;
}
return new GetCredentialProviderData.Builder(
- mComponentName.flattenToString()).setActionChips(null)
+ mComponentName.flattenToString())
+ .setActionChips(Collections.EMPTY_LIST)
+ .setAuthenticationEntries(Collections.EMPTY_LIST)
.setCredentialEntries(prepareUiCredentialEntries(
mProviderResponse.stream().flatMap((Function<CredentialDescriptionRegistry
.FilterResult,
@@ -261,12 +265,12 @@
.getFilteredResultForProvider(mCredentialProviderPackageName,
mElementKeys);
mCredentialEntries = mProviderResponse.stream().flatMap(
- (Function<CredentialDescriptionRegistry.FilterResult,
- Stream<CredentialEntry>>) filterResult
- -> filterResult.mCredentialEntries.stream())
- .collect(Collectors.toList());
+ (Function<CredentialDescriptionRegistry.FilterResult,
+ Stream<CredentialEntry>>)
+ filterResult -> filterResult.mCredentialEntries.stream())
+ .collect(Collectors.toList());
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED,
- /*source=*/ CredentialsSource.REGISTRY);
+ /*source=*/ CredentialsSource.REGISTRY);
mProviderSessionMetric.collectCandidateEntryMetrics(mCredentialEntries);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 31efcca..fc540d9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2055,14 +2055,17 @@
t.traceEnd();
}
- t.traceBegin("StartPacProxyService");
- try {
- pacProxyService = new PacProxyService(context);
- ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService);
- } catch (Throwable e) {
- reportWtf("starting PacProxyService", e);
+ // Devices without WebView/JavaScript cannot support PAC proxies.
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+ t.traceBegin("StartPacProxyService");
+ try {
+ pacProxyService = new PacProxyService(context);
+ ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService);
+ } catch (Throwable e) {
+ reportWtf("starting PacProxyService", e);
+ }
+ t.traceEnd();
}
- t.traceEnd();
t.traceBegin("StartConnectivityService");
// This has to be called after NetworkManagementService, NetworkStatsService
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index c60f184..17474fb 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -469,7 +469,7 @@
companion object {
private val LOG_TAG = AccessPolicy::class.java.simpleName
- internal const val VERSION_LATEST = 14
+ internal const val VERSION_LATEST = 15
private const val TAG_ACCESS = "access"
private const val TAG_DEFAULT_PERMISSION_GRANT = "default-permission-grant"
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
index 875183c..b644d8f 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
@@ -56,7 +56,7 @@
)
upgradeAccessMediaLocationPermission(packageState, userId)
}
- // Enable isAtLeastT check, when moving subsystem to mainline.
+ // TODO Enable isAtLeastT check, when moving subsystem to mainline.
if (version <= 12 /*&& SdkLevel.isAtLeastT()*/) {
Slog.v(
LOG_TAG, "Upgrading scoped permissions for package: $packageName" +
@@ -64,6 +64,14 @@
)
upgradeAuralVisualMediaPermissions(packageState, userId)
}
+ // TODO Enable isAtLeastU check, when moving subsystem to mainline.
+ if (version <= 14 /*&& SdkLevel.isAtLeastU()*/) {
+ Slog.v(
+ LOG_TAG, "Upgrading visual media permission for package: $packageName" +
+ ", version: $version, user: $userId"
+ )
+ upgradeUserSelectedVisualMediaPermission(packageState, userId)
+ }
// Add a new upgrade step: if (packageVersion <= LATEST_VERSION) { .... }
// Also increase LATEST_VERSION
}
@@ -127,6 +135,9 @@
}
}
+ /**
+ * Upgrade permissions based on storage permissions grant
+ */
private fun MutateStateScope.upgradeAuralVisualMediaPermissions(
packageState: PackageState,
userId: Int
@@ -154,6 +165,36 @@
}
}
+ /**
+ * Upgrade permission based on the grant in [Manifest.permission_group.READ_MEDIA_VISUAL]
+ */
+ private fun MutateStateScope.upgradeUserSelectedVisualMediaPermission(
+ packageState: PackageState,
+ userId: Int
+ ) {
+ val androidPackage = packageState.androidPackage!!
+ if (androidPackage.targetSdkVersion < Build.VERSION_CODES.TIRAMISU) {
+ return
+ }
+ val requestedPermissionNames = androidPackage.requestedPermissions
+ val isVisualMediaUserGranted = VISUAL_MEDIA_PERMISSIONS.anyIndexed { _, permissionName ->
+ if (permissionName !in requestedPermissionNames) {
+ return@anyIndexed false
+ }
+ val flags = with(policy) {
+ getPermissionFlags(packageState.appId, userId, permissionName)
+ }
+ PermissionFlags.isAppOpGranted(flags) && flags.hasBits(PermissionFlags.USER_SET)
+ }
+ if (isVisualMediaUserGranted) {
+ if (Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED in requestedPermissionNames) {
+ grantRuntimePermission(
+ packageState, userId, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+ )
+ }
+ }
+ }
+
private fun MutateStateScope.grantRuntimePermission(
packageState: PackageState,
userId: Int,
@@ -218,7 +259,14 @@
Manifest.permission.READ_MEDIA_AUDIO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VIDEO,
+ Manifest.permission.ACCESS_MEDIA_LOCATION,
Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
)
+ // Visual media permissions in T
+ private val VISUAL_MEDIA_PERMISSIONS = indexedSetOf(
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VIDEO,
+ Manifest.permission.ACCESS_MEDIA_LOCATION
+ )
}
}
diff --git a/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt b/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
index fa6b6b1..a61489c 100644
--- a/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
+++ b/services/permission/java/com/android/server/permission/access/util/PackageVersionMigration.kt
@@ -43,8 +43,9 @@
permissionVersion == -1 && appOpVersion == -1 ->
error("getVersion() called when there are no legacy files")
// merging combination of versions based on released android version
- // permissions version 1-8 were released in Q, 9 in S and 10 in T
+ // permissions version 1-8 were released in Q, 9 in S, 10 in T and 11 in U
// app ops version 1 was released in P, 3 in U.
+ permissionVersion >= 11 && appOpVersion >= 3 -> 15
permissionVersion >= 10 && appOpVersion >= 3 -> 14
permissionVersion >= 10 && appOpVersion >= 1 -> 13
permissionVersion >= 9 && appOpVersion >= 1 -> 12
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 73065a4..5b51963 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -143,6 +143,7 @@
import android.os.Message;
import android.os.PowerExemptionManager;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -2136,31 +2137,59 @@
assertEquals(deviceIdleUntil, mTestTimer.getElapsed());
- final PendingIntent pi5wakeup = getNewMockPendingIntent();
- final PendingIntent pi4wakeupPackage = getNewMockPendingIntent();
- final PendingIntent pi2nonWakeup = getNewMockPendingIntent(57, "test.different.package");
+ final PendingIntent pi4System = getNewMockPendingIntent(Process.SYSTEM_UID, "android");
+ final PendingIntent pi9System = getNewMockPendingIntent(Process.SYSTEM_UID, "android");
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, pi5wakeup);
- setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 4, pi4wakeupPackage);
+ final PendingIntent pi5wakeupPackage = getNewMockPendingIntent();
+ final IAlarmListener listener2WakeupPackage = getNewListener(() -> {});
+ final PendingIntent pi4wakeupPackage = getNewMockPendingIntent(41, "test.wakeup.package2");
+ final PendingIntent pi19wakeupPackage = getNewMockPendingIntent(41, "test.wakeup.package2");
+
+ final PendingIntent pi2nonWakeup = getNewMockPendingIntent(57, "test.nonwakeup.package1");
+ final PendingIntent pi8nonWakeup = getNewMockPendingIntent(59, "test.nonwakeup.package2");
+ final PendingIntent pi11nonWakeup = getNewMockPendingIntent(51, "test.nonwakeup.package3");
+
+ // Alarms from the system
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 4, pi4System);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 9, pi9System);
+
+ // Alarms from TEST_CALLING_PACKAGE, TEST_CALLING_UID, having one wakeup alarm
+ setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + 20, mService.mTimeTickTrigger);
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, pi5wakeupPackage);
+ setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + 2, listener2WakeupPackage);
+
+ // Alarms from 41, "test.wakeup.package2", having one wakeup alarm
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 4, pi4wakeupPackage);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 19, pi19wakeupPackage);
+
+ // Alarms from other packages having no wakeup alarms
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 8, pi8nonWakeup);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 11, pi11nonWakeup);
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 2, pi2nonWakeup);
mNowElapsedTest = deviceIdleUntil;
mTestTimer.expire();
- // The order of the alarms in delivery list should be:
- // IdleUntil, all alarms of a package with any wakeup alarms, then the rest.
- // Within a package, alarms should be ordered by requested delivery time.
- final PendingIntent[] expectedOrder = new PendingIntent[]{
- idleUntilPi, pi4wakeupPackage, pi5wakeup, pi2nonWakeup};
+ // IdleUntil should always go out first. The others are divided into three classes:
+ // System alarms | Alarms of packages with any wakeup alarms | Others.
+ // Within each class, time_tick should go first if present, others should be ordered by
+ // requested delivery time.
+ final PendingIntent[] expectedPiOrder = new PendingIntent[]{
+ idleUntilPi, pi4System, pi9System, null, null, pi4wakeupPackage, pi5wakeupPackage,
+ pi19wakeupPackage, pi2nonWakeup, pi8nonWakeup, pi11nonWakeup};
+
+ final IAlarmListener[] expectedListenerOrder = new IAlarmListener[expectedPiOrder.length];
+ expectedListenerOrder[3] = mService.mTimeTickTrigger;
+ expectedListenerOrder[4] = listener2WakeupPackage;
ArgumentCaptor<ArrayList<Alarm>> listCaptor = ArgumentCaptor.forClass(ArrayList.class);
verify(mService).deliverAlarmsLocked(listCaptor.capture(), anyLong());
final ArrayList<Alarm> deliveryList = listCaptor.getValue();
- assertEquals(expectedOrder.length, deliveryList.size());
- for (int i = 0; i < expectedOrder.length; i++) {
+ assertEquals(expectedPiOrder.length, deliveryList.size());
+ for (int i = 0; i < expectedPiOrder.length; i++) {
assertTrue("Unexpected alarm: " + deliveryList.get(i) + " at pos: " + i,
- deliveryList.get(i).matches(expectedOrder[i], null));
+ deliveryList.get(i).matches(expectedPiOrder[i], expectedListenerOrder[i]));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index 70ee4f4..0abf46b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -131,6 +131,7 @@
mRealAms = new ActivityManagerService(
new TestInjector(mContext), mServiceThreadRule.getThread());
+ mRealAms.mConstants.loadDeviceConfigConstants();
mRealAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
mRealAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
mRealAms.mAtmInternal = mActivityTaskManagerInt;
@@ -195,7 +196,9 @@
Log.v(TAG, "Intercepting bindApplication() for "
+ Arrays.toString(invocation.getArguments()));
if (!wedge) {
- mRealAms.finishAttachApplication(0);
+ if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
+ mRealAms.finishAttachApplication(0);
+ }
}
return null;
}).when(thread).bindApplication(
@@ -237,9 +240,10 @@
*/
@Test
public void testNormal() throws Exception {
- ProcessRecord app = startProcessAndWait(false);
-
- verify(app, never()).killLocked(any(), anyInt(), anyBoolean());
+ if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
+ ProcessRecord app = startProcessAndWait(false);
+ verify(app, never()).killLocked(any(), anyInt(), anyBoolean());
+ }
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index bad04dc..fe23eee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -2439,6 +2439,13 @@
doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
.when(mPermissionManagerServiceInternal)
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
+ try {
+ doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
+ .when(mIActivityManager)
+ .checkPermission(perm, Process.INVALID_PID, uid);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
}
private void setAppOpState(String packageName, int uid, int op, boolean granted) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 1542112..ff04728 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -66,6 +66,7 @@
import android.annotation.NonNull;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
@@ -410,9 +411,9 @@
List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
- queue.setProcessAndUidState(null, false, false);
+ queue.setProcessAndUidState(mProcess, false, false);
final long notCachedRunnableAt = queue.getRunnableAt();
- queue.setProcessAndUidState(null, false, true);
+ queue.setProcessAndUidState(mProcess, false, true);
final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertFalse(queue.isRunnable());
@@ -437,9 +438,9 @@
List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
- queue.setProcessAndUidState(null, false, false);
+ queue.setProcessAndUidState(mProcess, false, false);
final long notCachedRunnableAt = queue.getRunnableAt();
- queue.setProcessAndUidState(null, false, true);
+ queue.setProcessAndUidState(mProcess, false, true);
final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertTrue(queue.isRunnable());
@@ -555,6 +556,33 @@
}
@Test
+ public void testRunnableAt_processTop() {
+ final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+
+ doReturn(ActivityManager.PROCESS_STATE_TOP).when(mProcess).getSetProcState();
+ queue.setProcessAndUidState(mProcess, false, false);
+
+ final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+ final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
+ List.of(makeMockRegisteredReceiver()));
+ enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
+
+ assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_TOP_PROCESS, queue.getRunnableAtReason());
+
+ doReturn(ActivityManager.PROCESS_STATE_SERVICE).when(mProcess).getSetProcState();
+ queue.setProcessAndUidState(mProcess, false, false);
+
+ // The new process state will only be taken into account the next time a broadcast
+ // is sent to the process.
+ enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick,
+ List.of(makeMockRegisteredReceiver())), 0);
+ assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
+ }
+
+ @Test
public void testRunnableAt_persistentProc() {
final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
getUidForPackage(PACKAGE_GREEN));
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 0f75ea5..73eb237 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -172,6 +172,7 @@
BroadcastConstants mConstants;
private BroadcastSkipPolicy mSkipPolicy;
private UidObserver mUidObserver;
+ private UidObserver mUidCachedStateObserver;
/**
* Desired behavior of the next
@@ -261,6 +262,7 @@
// Create a different process that will be linked to the
// returned process via a predecessor/successor relationship
mActiveProcesses.remove(res);
+ res.setKilled(true);
deliverRes = makeActiveProcessRecord(ai, processName,
ProcessBehavior.NORMAL, UnaryOperator.identity());
deliverRes.mPredecessor = res;
@@ -316,7 +318,13 @@
doAnswer((invocation) -> {
mUidObserver = invocation.getArgument(0);
return null;
- }).when(mAms).registerUidObserver(any(), anyInt(), anyInt(), any());
+ }).when(mAms).registerUidObserver(any(), anyInt(),
+ eq(ActivityManager.PROCESS_STATE_TOP), any());
+ doAnswer((invocation) -> {
+ mUidCachedStateObserver = invocation.getArgument(0);
+ return null;
+ }).when(mAms).registerUidObserver(any(), anyInt(),
+ eq(ActivityManager.PROCESS_STATE_LAST_ACTIVITY), any());
mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
mConstants.TIMEOUT = 100;
@@ -413,6 +421,12 @@
UserHandle.USER_SYSTEM);
}
+ private ProcessRecord makeActiveProcessRecord(String packageName, String processName)
+ throws Exception {
+ return makeActiveProcessRecord(packageName, processName, ProcessBehavior.NORMAL,
+ UserHandle.USER_SYSTEM);
+ }
+
private ProcessRecord makeActiveProcessRecord(String packageName,
ProcessBehavior behavior) throws Exception {
return makeActiveProcessRecord(packageName, packageName, behavior, UserHandle.USER_SYSTEM);
@@ -615,6 +629,11 @@
BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN);
}
+ private void setProcessFreezable(ProcessRecord app, boolean pendingFreeze, boolean frozen) {
+ app.mOptRecord.setPendingFreeze(pendingFreeze);
+ app.mOptRecord.setFrozen(frozen);
+ }
+
private void assertHealth() {
if (mImpl == Impl.MODERN) {
// If this fails, it'll throw a clear reason message
@@ -1316,6 +1335,53 @@
verifyScheduleReceiver(times(1), receiverOrangeApp, timezone);
}
+ /**
+ * Verify that a broadcast sent to a frozen app, which gets killed as part of unfreezing
+ * process due to pending sync binder transactions, is delivered as expected.
+ */
+ @Test
+ public void testDeliveryToFrozenApp_killedWhileUnfreeze() throws Exception {
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
+
+ // Mark the app as killed while unfreezing it, which can happen either when we directly
+ // try to unfreeze it or when it is done as part of OomAdjust computation.
+ doAnswer(invocation -> {
+ final ProcessRecord app = invocation.getArgument(0);
+ if (app == receiverBlueApp) {
+ app.setKilled(true);
+ mActiveProcesses.remove(app);
+ }
+ return null;
+ }).when(mAms.mOomAdjuster).unfreezeTemporarily(eq(receiverBlueApp), anyInt());
+ doAnswer(invocation -> {
+ final ProcessRecord app = invocation.getArgument(0);
+ if (app == receiverBlueApp) {
+ app.setKilled(true);
+ mActiveProcesses.remove(app);
+ }
+ return null;
+ }).when(mAms).enqueueOomAdjTargetLocked(eq(receiverBlueApp));
+
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
+ makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
+
+ waitForIdle();
+ final ProcessRecord restartedReceiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
+ getUidForPackage(PACKAGE_BLUE));
+ assertNotEquals(receiverBlueApp, restartedReceiverBlueApp);
+ // Legacy queue will always try delivering the broadcast even if the process
+ // has been killed.
+ if (mImpl == Impl.MODERN) {
+ verifyScheduleReceiver(never(), receiverBlueApp, airplane);
+ } else {
+ verifyScheduleReceiver(times(1), receiverBlueApp, airplane);
+ }
+ // Verify that the new process receives the broadcast.
+ verifyScheduleReceiver(times(1), restartedReceiverBlueApp, airplane);
+ }
+
@Test
public void testCold_Success() throws Exception {
doCold(ProcessStartBehavior.SUCCESS);
@@ -1714,8 +1780,10 @@
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
+ setProcessFreezable(receiverGreenApp, true, false);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
+ setProcessFreezable(receiverBlueApp, false, true);
+ mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -1759,12 +1827,14 @@
eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
// Shift blue to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false);
+ setProcessFreezable(receiverBlueApp, false, false);
+ mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
// Shift green to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+ setProcessFreezable(receiverGreenApp, false, false);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
}
@@ -2189,9 +2259,12 @@
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false);
+ setProcessFreezable(receiverGreenApp, true, true);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
+ setProcessFreezable(receiverBlueApp, true, false);
+ mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
+ setProcessFreezable(receiverYellowApp, false, false);
+ mQueue.onProcessFreezableChangedLocked(receiverYellowApp);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -2214,11 +2287,50 @@
verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
// Shift green to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+ setProcessFreezable(receiverGreenApp, false, false);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
}
+ /**
+ * Verify broadcasts to a runtime receiver in cached process is deferred even when a different
+ * process in the same package is not cached.
+ */
+ @Test
+ public void testDeferralPolicy_UntilActive_WithMultiProcessUid() throws Exception {
+ // Legacy stack doesn't support deferral
+ Assume.assumeTrue(mImpl == Impl.MODERN);
+
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ final ProcessRecord receiverGreenApp1 = makeActiveProcessRecord(PACKAGE_GREEN);
+ final ProcessRecord receiverGreenApp2 = makeActiveProcessRecord(PACKAGE_GREEN,
+ PACKAGE_GREEN + "_proc2");
+
+ setProcessFreezable(receiverGreenApp1, true, true);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
+
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ final BroadcastOptions opts = BroadcastOptions.makeBasic()
+ .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, opts,
+ List.of(makeRegisteredReceiver(receiverGreenApp1),
+ makeRegisteredReceiver(receiverGreenApp2))));
+ waitForIdle();
+
+ // 1st process in Green package is ignored since it is in a cached state
+ // but the 2nd process should still receive the broadcast.
+ verifyScheduleRegisteredReceiver(never(), receiverGreenApp1, airplane);
+ verifyScheduleRegisteredReceiver(times(1), receiverGreenApp2, airplane);
+
+ // Shift the 1st process in Green package to be active and confirm that deferred broadcast
+ // is delivered
+ setProcessFreezable(receiverGreenApp1, false, false);
+ mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
+ waitForIdle();
+ verifyScheduleRegisteredReceiver(times(1), receiverGreenApp1, airplane);
+ }
+
@Test
public void testBroadcastDelivery_uidForeground() throws Exception {
// Legacy stack doesn't support prioritization to foreground app.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 770f04a..1f4563f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1971,6 +1971,36 @@
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoOne_PendingFinishAttach() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ app.setPendingFinishAttach(true);
+ app.mState.setHasForegroundActivities(false);
+
+ sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ updateOomAdj(app);
+
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoOne_TopApp_PendingFinishAttach() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ app.setPendingFinishAttach(true);
+ app.mState.setHasForegroundActivities(true);
+
+ sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ updateOomAdj(app);
+
+ assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ,
+ SCHED_GROUP_TOP_APP);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_UidIdle_StopService() {
final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
@@ -2512,6 +2542,35 @@
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_Side_Cycle() {
+ final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+ long now = SystemClock.uptimeMillis();
+ ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class));
+ s.startRequested = true;
+ s.lastActivity = now;
+ s = bindService(app2, app3, null, 0, mock(IBinder.class));
+ s.lastActivity = now;
+ s = bindService(app3, app2, null, 0, mock(IBinder.class));
+ s.lastActivity = now;
+
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ sService.mOomAdjuster.mNumServiceProcs = 3;
+ updateOomAdj(app, app2, app3);
+
+ assertEquals(SERVICE_ADJ, app.mState.getSetAdj());
+ assertTrue(sFirstCachedAdj <= app2.mState.getSetAdj());
+ assertTrue(sFirstCachedAdj <= app3.mState.getSetAdj());
+ assertTrue(CACHED_APP_MAX_ADJ >= app2.mState.getSetAdj());
+ assertTrue(CACHED_APP_MAX_ADJ >= app3.mState.getSetAdj());
+ }
+
private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
String packageName, boolean hasShownUi) {
long now = SystemClock.uptimeMillis();
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index de5e6d7..434a75f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -46,6 +46,7 @@
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
@@ -95,6 +96,10 @@
private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1;
private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789";
private static final float PROX_SENSOR_MAX_RANGE = 5;
+ private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f;
+ private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
+ private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
+ private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
private OffsettableClock mClock;
private TestLooper mTestLooper;
@@ -296,6 +301,8 @@
public void testDisplayBrightnessFollowers_BothDpcsSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -334,14 +341,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -362,14 +373,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -388,14 +403,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -416,8 +435,10 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
@@ -425,24 +446,70 @@
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- final float brightness = 0.4f;
- final float nits = 300;
- final float ambientLux = 3000;
- when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
- .thenReturn(brightness);
- when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
- .thenReturn(0.3f);
- when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ DisplayPowerControllerHolder followerDpc =
+ createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
- DisplayPowerController2 followerDpc = mock(DisplayPowerController2.class);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ float leadBrightness = 0.1f;
+ float rawLeadBrightness = 0.3f;
+ float followerBrightness = 0.4f;
+ float nits = 300;
+ float ambientLux = 3000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(rawLeadBrightness);
+ when(mHolder.automaticBrightnessController
+ .getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+ .thenReturn(leadBrightness);
+ when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
+ .thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ .thenReturn(followerBrightness);
- mHolder.dpc.addDisplayBrightnessFollower(followerDpc);
+ mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
+
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
- verify(followerDpc).setBrightnessToFollow(brightness, nits, ambientLux);
+ verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ // One triggered by handleBrightnessModeChange, another triggered by setBrightnessToFollow
+ verify(followerDpc.hbmController, times(2)).onAmbientLuxChange(ambientLux);
+ verify(followerDpc.animator, times(2)).animateTo(eq(followerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness);
+ when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness);
+ clearInvocations(mHolder.animator, followerDpc.animator);
+
+ leadBrightness = 0.05f;
+ rawLeadBrightness = 0.2f;
+ followerBrightness = 0.3f;
+ nits = 200;
+ ambientLux = 2000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(rawLeadBrightness);
+ when(mHolder.automaticBrightnessController
+ .getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+ .thenReturn(leadBrightness);
+ when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
+ .thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ .thenReturn(followerBrightness);
+
+ mHolder.dpc.updateBrightness();
+ advanceTime(1); // Run updatePowerState
+
+ // The second time, the animation rate should be slow
+ verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE));
+ verify(followerDpc.hbmController).onAmbientLuxChange(ambientLux);
+ verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE));
}
@Test
@@ -451,6 +518,9 @@
FOLLOWER_UNIQUE_ID);
DisplayPowerControllerHolder secondFollowerDpc = createDisplayPowerController(
SECOND_FOLLOWER_DISPLAY_ID, SECOND_FOLLOWER_UNIQUE_DISPLAY_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(secondFollowerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -472,9 +542,11 @@
when(followerDpc.brightnessSetting.getBrightness()).thenReturn(initialFollowerBrightness);
followerListener.onBrightnessChanged(initialFollowerBrightness);
advanceTime(1);
- verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ when(followerDpc.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
mHolder.dpc.addDisplayBrightnessFollower(secondFollowerDpc.dpc);
@@ -491,17 +563,26 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(secondFollowerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness);
clearInvocations(mHolder.animator, followerDpc.animator, secondFollowerDpc.animator);
// Remove the first follower and validate it goes back to its original brightness.
mHolder.dpc.removeDisplayBrightnessFollower(followerDpc.dpc);
advanceTime(1);
- verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
+
+ when(followerDpc.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
clearInvocations(followerDpc.animator);
// Change the brightness of the lead display and validate only the second follower responds
@@ -515,9 +596,11 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
verify(followerDpc.animator, never()).animateTo(anyFloat(), anyFloat(), anyFloat());
- verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
@@ -527,6 +610,9 @@
DisplayPowerControllerHolder secondFollowerHolder =
createDisplayPowerController(SECOND_FOLLOWER_DISPLAY_ID,
SECOND_FOLLOWER_UNIQUE_DISPLAY_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(secondFollowerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -556,10 +642,15 @@
followerListener.onBrightnessChanged(initialFollowerBrightness);
secondFollowerListener.onBrightnessChanged(initialFollowerBrightness);
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+ when(followerHolder.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
+ when(secondFollowerHolder.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc);
mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc);
@@ -576,19 +667,25 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(followerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(secondFollowerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
clearInvocations(mHolder.animator, followerHolder.animator, secondFollowerHolder.animator);
// Stop the lead DPC and validate that the followers go back to their original brightness.
mHolder.dpc.stop();
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
clearInvocations(followerHolder.animator, secondFollowerHolder.animator);
}
@@ -748,6 +845,155 @@
}
@Test
+ public void testAutoBrightnessEnabled_DisplayIsOn() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_DisplayIsInDoze() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_ManualBrightnessMode() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // One triggered by the test, the other by handleBrightnessModeChange
+ verify(mHolder.automaticBrightnessController, times(2)).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController, times(2))
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_DisplayIsOff() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_OFF,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController).setAutoBrightnessEnabled(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_DisplayIsInDoze() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController).setAutoBrightnessEnabled(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_FollowerDisplay() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mHolder.dpc.setBrightnessToFollow(0.3f, -1, 0, /* slowChange= */ false);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // One triggered by the test, the other by handleBrightnessModeChange
+ verify(mHolder.automaticBrightnessController, times(2)).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+
+ // HBM should be allowed for the follower display
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
public void testBrightnessNitsPersistWhenDisplayDeviceChanges() {
float brightness = 0.3f;
float nits = 500;
@@ -903,6 +1149,14 @@
});
when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
.thenReturn(new int[0]);
+ when(displayDeviceConfigMock.getBrightnessRampFastDecrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_DECREASE);
+ when(displayDeviceConfigMock.getBrightnessRampFastIncrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_INCREASE);
+ when(displayDeviceConfigMock.getBrightnessRampSlowDecrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
+ when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
}
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
@@ -922,10 +1176,13 @@
final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class);
final ScreenOffBrightnessSensorController screenOffBrightnessSensorController =
mock(ScreenOffBrightnessSensorController.class);
+ final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class);
+
+ when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX);
TestInjector injector = spy(new TestInjector(displayPowerState, animator,
automaticBrightnessController, wakelockController, brightnessMappingStrategy,
- hysteresisLevels, screenOffBrightnessSensorController));
+ hysteresisLevels, screenOffBrightnessSensorController, hbmController));
final LogicalDisplay display = mock(LogicalDisplay.class);
final DisplayDevice device = mock(DisplayDevice.class);
@@ -943,8 +1200,8 @@
return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting,
animator, automaticBrightnessController, wakelockController,
- screenOffBrightnessSensorController, hbmMetadata, brightnessMappingStrategy,
- injector);
+ screenOffBrightnessSensorController, hbmController, hbmMetadata,
+ brightnessMappingStrategy, injector);
}
/**
@@ -960,6 +1217,7 @@
public final AutomaticBrightnessController automaticBrightnessController;
public final WakelockController wakelockController;
public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController;
+ public final HighBrightnessModeController hbmController;
public final HighBrightnessModeMetadata hbmMetadata;
public final BrightnessMappingStrategy brightnessMappingStrategy;
public final DisplayPowerController2.Injector injector;
@@ -970,6 +1228,7 @@
AutomaticBrightnessController automaticBrightnessController,
WakelockController wakelockController,
ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeController hbmController,
HighBrightnessModeMetadata hbmMetadata,
BrightnessMappingStrategy brightnessMappingStrategy,
DisplayPowerController2.Injector injector) {
@@ -981,6 +1240,7 @@
this.automaticBrightnessController = automaticBrightnessController;
this.wakelockController = wakelockController;
this.screenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ this.hbmController = hbmController;
this.hbmMetadata = hbmMetadata;
this.brightnessMappingStrategy = brightnessMappingStrategy;
this.injector = injector;
@@ -995,13 +1255,15 @@
private final BrightnessMappingStrategy mBrightnessMappingStrategy;
private final HysteresisLevels mHysteresisLevels;
private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
+ private final HighBrightnessModeController mHighBrightnessModeController;
TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
WakelockController wakelockController,
BrightnessMappingStrategy brightnessMappingStrategy,
HysteresisLevels hysteresisLevels,
- ScreenOffBrightnessSensorController screenOffBrightnessSensorController) {
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeController highBrightnessModeController) {
mDisplayPowerState = dps;
mAnimator = animator;
mAutomaticBrightnessController = automaticBrightnessController;
@@ -1009,6 +1271,7 @@
mBrightnessMappingStrategy = brightnessMappingStrategy;
mHysteresisLevels = hysteresisLevels;
mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ mHighBrightnessModeController = highBrightnessModeController;
}
@Override
@@ -1102,5 +1365,15 @@
BrightnessMappingStrategy brightnessMapper) {
return mScreenOffBrightnessSensorController;
}
+
+ @Override
+ HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
+ int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
+ float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
+ Context context) {
+ return mHighBrightnessModeController;
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 95bc26a..db786bd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -46,6 +46,7 @@
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
@@ -95,6 +96,10 @@
private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1;
private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789";
private static final float PROX_SENSOR_MAX_RANGE = 5;
+ private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f;
+ private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
+ private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
+ private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
private OffsettableClock mClock;
private TestLooper mTestLooper;
@@ -299,6 +304,8 @@
public void testDisplayBrightnessFollowers_BothDpcsSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -322,10 +329,13 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness);
listener.onBrightnessChanged(leadBrightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(),
- anyFloat());
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness);
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness);
clearInvocations(mHolder.animator, followerDpc.animator);
// Test the same float scale value
@@ -337,14 +347,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -365,14 +379,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -391,14 +409,18 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -419,8 +441,10 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
@@ -428,38 +452,86 @@
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- final float brightness = 0.4f;
- final float nits = 300;
- final float ambientLux = 3000;
- when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
- .thenReturn(brightness);
- when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness())
- .thenReturn(0.3f);
- when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ DisplayPowerControllerHolder followerDpc =
+ createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
- DisplayPowerController followerDpc = mock(DisplayPowerController.class);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ float leadBrightness = 0.1f;
+ float rawLeadBrightness = 0.3f;
+ float followerBrightness = 0.4f;
+ float nits = 300;
+ float ambientLux = 3000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(rawLeadBrightness);
+ when(mHolder.automaticBrightnessController
+ .getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+ .thenReturn(leadBrightness);
+ when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
+ .thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ .thenReturn(followerBrightness);
- mHolder.dpc.addDisplayBrightnessFollower(followerDpc);
+ mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
+
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
- verify(followerDpc).setBrightnessToFollow(brightness, nits, ambientLux);
+ verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ // One triggered by handleBrightnessModeChange, another triggered by setBrightnessToFollow
+ verify(followerDpc.hbmController, times(2)).onAmbientLuxChange(ambientLux);
+ verify(followerDpc.animator, times(2)).animateTo(eq(followerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness);
+ when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness);
+ clearInvocations(mHolder.animator, followerDpc.animator);
+
+ leadBrightness = 0.05f;
+ rawLeadBrightness = 0.2f;
+ followerBrightness = 0.3f;
+ nits = 200;
+ ambientLux = 2000;
+ when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness())
+ .thenReturn(rawLeadBrightness);
+ when(mHolder.automaticBrightnessController
+ .getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+ .thenReturn(leadBrightness);
+ when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
+ .thenReturn(nits);
+ when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ .thenReturn(followerBrightness);
+
+ mHolder.dpc.updateBrightness();
+ advanceTime(1); // Run updatePowerState
+
+ // The second time, the animation rate should be slow
+ verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE));
+ verify(followerDpc.hbmController).onAmbientLuxChange(ambientLux);
+ verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE));
}
@Test
public void testDisplayBrightnessFollowersRemoval_RemoveSingleFollower() {
- DisplayPowerControllerHolder followerHolder =
- createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
- DisplayPowerControllerHolder secondFollowerHolder =
- createDisplayPowerController(SECOND_FOLLOWER_DISPLAY_ID,
- SECOND_FOLLOWER_UNIQUE_DISPLAY_ID);
+ DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID,
+ FOLLOWER_UNIQUE_ID);
+ DisplayPowerControllerHolder secondFollowerDpc = createDisplayPowerController(
+ SECOND_FOLLOWER_DISPLAY_ID, SECOND_FOLLOWER_UNIQUE_DISPLAY_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(secondFollowerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- followerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- secondFollowerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ secondFollowerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor =
@@ -470,58 +542,71 @@
// Set the initial brightness on the DPC we're going to remove so we have a fixed value for
// it to return to.
listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class);
- verify(followerHolder.brightnessSetting).registerListener(listenerCaptor.capture());
+ verify(followerDpc.brightnessSetting).registerListener(listenerCaptor.capture());
BrightnessSetting.BrightnessSettingListener followerListener = listenerCaptor.getValue();
final float initialFollowerBrightness = 0.3f;
- when(followerHolder.brightnessSetting.getBrightness()).thenReturn(
- initialFollowerBrightness);
+ when(followerDpc.brightnessSetting.getBrightness()).thenReturn(initialFollowerBrightness);
followerListener.onBrightnessChanged(initialFollowerBrightness);
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
- mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc);
- mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc);
- clearInvocations(followerHolder.animator);
+ when(followerDpc.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
+
+ mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
+ mHolder.dpc.addDisplayBrightnessFollower(secondFollowerDpc.dpc);
+ clearInvocations(followerDpc.animator);
// Validate both followers are correctly registered and receiving brightness updates
float brightness = 0.6f;
float nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
.thenReturn(brightness);
- when(secondFollowerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
- clearInvocations(mHolder.animator, followerHolder.animator, secondFollowerHolder.animator);
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(secondFollowerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ clearInvocations(mHolder.animator, followerDpc.animator, secondFollowerDpc.animator);
// Remove the first follower and validate it goes back to its original brightness.
- mHolder.dpc.removeDisplayBrightnessFollower(followerHolder.dpc);
+ mHolder.dpc.removeDisplayBrightnessFollower(followerDpc.dpc);
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
- clearInvocations(followerHolder.animator);
+ verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
+
+ when(followerDpc.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
+ clearInvocations(followerDpc.animator);
// Change the brightness of the lead display and validate only the second follower responds
brightness = 0.7f;
nits = 700;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
.thenReturn(brightness);
- when(secondFollowerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerHolder.animator, never()).animateTo(anyFloat(), anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerDpc.animator, never()).animateTo(anyFloat(), anyFloat(), anyFloat());
+ verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
}
@Test
@@ -531,6 +616,9 @@
DisplayPowerControllerHolder secondFollowerHolder =
createDisplayPowerController(SECOND_FOLLOWER_DISPLAY_ID,
SECOND_FOLLOWER_UNIQUE_DISPLAY_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(followerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(secondFollowerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -560,10 +648,15 @@
followerListener.onBrightnessChanged(initialFollowerBrightness);
secondFollowerListener.onBrightnessChanged(initialFollowerBrightness);
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+ when(followerHolder.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
+ when(secondFollowerHolder.displayPowerState.getScreenBrightness())
+ .thenReturn(initialFollowerBrightness);
mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc);
mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc);
@@ -580,19 +673,25 @@
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
advanceTime(1); // Send messages, run updatePowerState
- verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat());
+ verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+ when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(followerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+ when(secondFollowerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
clearInvocations(mHolder.animator, followerHolder.animator, secondFollowerHolder.animator);
// Stop the lead DPC and validate that the followers go back to their original brightness.
mHolder.dpc.stop();
advanceTime(1);
- verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
- verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness),
- anyFloat(), anyFloat());
+ verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
+ verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE));
clearInvocations(followerHolder.animator, secondFollowerHolder.animator);
}
@@ -751,6 +850,155 @@
}
@Test
+ public void testAutoBrightnessEnabled_DisplayIsOn() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessEnabled_DisplayIsInDoze() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_ManualBrightnessMode() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // One triggered by the test, the other by handleBrightnessModeChange
+ verify(mHolder.automaticBrightnessController, times(2)).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController, times(2))
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_DisplayIsOff() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_OFF,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController).setAutoBrightnessEnabled(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_DisplayIsInDoze() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.automaticBrightnessController).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+ /* shouldResetShortTermModel= */ false
+ );
+ verify(mHolder.hbmController).setAutoBrightnessEnabled(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
+ }
+
+ @Test
+ public void testAutoBrightnessDisabled_FollowerDisplay() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ mHolder.dpc.setBrightnessToFollow(0.3f, -1, 0, /* slowChange= */ false);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // One triggered by the test, the other by handleBrightnessModeChange
+ verify(mHolder.automaticBrightnessController, times(2)).configure(
+ AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+ /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ /* userChangedBrightness= */ false, /* adjustment= */ 0,
+ /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ false
+ );
+
+ // HBM should be allowed for the follower display
+ verify(mHolder.hbmController)
+ .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+ }
+
+ @Test
public void testBrightnessNitsPersistWhenDisplayDeviceChanges() {
float brightness = 0.3f;
float nits = 500;
@@ -907,6 +1155,14 @@
});
when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux())
.thenReturn(new int[0]);
+ when(displayDeviceConfigMock.getBrightnessRampFastDecrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_DECREASE);
+ when(displayDeviceConfigMock.getBrightnessRampFastIncrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_INCREASE);
+ when(displayDeviceConfigMock.getBrightnessRampSlowDecrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
+ when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
+ .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
}
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
@@ -925,10 +1181,13 @@
final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class);
final ScreenOffBrightnessSensorController screenOffBrightnessSensorController =
mock(ScreenOffBrightnessSensorController.class);
+ final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class);
+
+ when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX);
DisplayPowerController.Injector injector = spy(new TestInjector(displayPowerState, animator,
automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels,
- screenOffBrightnessSensorController));
+ screenOffBrightnessSensorController, hbmController));
final LogicalDisplay display = mock(LogicalDisplay.class);
final DisplayDevice device = mock(DisplayDevice.class);
@@ -946,7 +1205,7 @@
return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting,
animator, automaticBrightnessController, screenOffBrightnessSensorController,
- hbmMetadata, brightnessMappingStrategy, injector);
+ hbmController, hbmMetadata, brightnessMappingStrategy, injector);
}
/**
@@ -961,6 +1220,7 @@
public final DualRampAnimator<DisplayPowerState> animator;
public final AutomaticBrightnessController automaticBrightnessController;
public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController;
+ public final HighBrightnessModeController hbmController;
public final HighBrightnessModeMetadata hbmMetadata;
public final BrightnessMappingStrategy brightnessMappingStrategy;
public final DisplayPowerController.Injector injector;
@@ -970,6 +1230,7 @@
DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeController hbmController,
HighBrightnessModeMetadata hbmMetadata,
BrightnessMappingStrategy brightnessMappingStrategy,
DisplayPowerController.Injector injector) {
@@ -980,6 +1241,7 @@
this.animator = animator;
this.automaticBrightnessController = automaticBrightnessController;
this.screenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ this.hbmController = hbmController;
this.hbmMetadata = hbmMetadata;
this.brightnessMappingStrategy = brightnessMappingStrategy;
this.injector = injector;
@@ -993,18 +1255,21 @@
private final BrightnessMappingStrategy mBrightnessMappingStrategy;
private final HysteresisLevels mHysteresisLevels;
private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
+ private final HighBrightnessModeController mHighBrightnessModeController;
TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator,
AutomaticBrightnessController automaticBrightnessController,
BrightnessMappingStrategy brightnessMappingStrategy,
HysteresisLevels hysteresisLevels,
- ScreenOffBrightnessSensorController screenOffBrightnessSensorController) {
+ ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
+ HighBrightnessModeController highBrightnessModeController) {
mDisplayPowerState = dps;
mAnimator = animator;
mAutomaticBrightnessController = automaticBrightnessController;
mBrightnessMappingStrategy = brightnessMappingStrategy;
mHysteresisLevels = hysteresisLevels;
mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
+ mHighBrightnessModeController = highBrightnessModeController;
}
@Override
@@ -1076,5 +1341,15 @@
BrightnessMappingStrategy brightnessMapper) {
return mScreenOffBrightnessSensorController;
}
+
+ @Override
+ HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width,
+ int height, IBinder displayToken, String displayUniqueId, float brightnessMin,
+ float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData,
+ HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata,
+ Context context) {
+ return mHighBrightnessModeController;
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java
index 5b0b989..534a708 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java
@@ -34,8 +34,8 @@
import android.os.test.TestLooper;
import android.view.Display;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.testutils.OffsettableClock;
@@ -92,7 +92,7 @@
};
mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mTestLooper.getLooper(),
- mNudgeUpdatePowerState, 0,
+ mNudgeUpdatePowerState, Display.DEFAULT_DISPLAY,
mSensorManager, injector);
mSensorEventListener = mDisplayPowerProximityStateController.getProximitySensorListener();
}
@@ -128,7 +128,7 @@
enableProximitySensor();
emitAndValidatePositiveProximityEvent();
mDisplayPowerProximityStateController.ignoreProximitySensorUntilChangedInternal();
- advanceTime(1);
+ advanceTime();
assertTrue(mDisplayPowerProximityStateController.shouldIgnoreProximityUntilChanged());
verify(mNudgeUpdatePowerState, times(2)).run();
@@ -170,7 +170,7 @@
}
@Test
- public void isProximitySensorAvailableReturnsFalseWhenNotAvailable() {
+ public void isProximitySensorAvailableReturnsFalseWhenNotAvailableAndNoDefault() {
when(mDisplayDeviceConfig.getProximitySensor()).thenReturn(
new DisplayDeviceConfig.SensorData() {
{
@@ -180,12 +180,63 @@
});
mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mTestLooper.getLooper(),
+ mNudgeUpdatePowerState, Display.DEFAULT_DISPLAY,
+ mSensorManager, null);
+ assertFalse(mDisplayPowerProximityStateController.isProximitySensorAvailable());
+ }
+
+ @Test
+ public void isProximitySensorAvailableReturnsTrueWhenNotAvailableAndHasDefault()
+ throws Exception {
+ when(mDisplayDeviceConfig.getProximitySensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = null;
+ name = null;
+ }
+ });
+ when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(
+ TestUtils.createSensor(Sensor.TYPE_PROXIMITY, "proximity"));
+ mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(
+ mWakelockController, mDisplayDeviceConfig, mTestLooper.getLooper(),
+ mNudgeUpdatePowerState, Display.DEFAULT_DISPLAY,
+ mSensorManager, null);
+ assertTrue(mDisplayPowerProximityStateController.isProximitySensorAvailable());
+ }
+
+ @Test
+ public void isProximitySensorAvailableReturnsFalseWhenNotAvailableHasDefaultNonDefaultDisplay()
+ throws Exception {
+ when(mDisplayDeviceConfig.getProximitySensor()).thenReturn(
+ new DisplayDeviceConfig.SensorData() {
+ {
+ type = null;
+ name = null;
+ }
+ });
+ when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(
+ TestUtils.createSensor(Sensor.TYPE_PROXIMITY, "proximity"));
+ mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(
+ mWakelockController, mDisplayDeviceConfig, mTestLooper.getLooper(),
mNudgeUpdatePowerState, 1,
mSensorManager, null);
assertFalse(mDisplayPowerProximityStateController.isProximitySensorAvailable());
}
@Test
+ public void isProximitySensorAvailableReturnsTrueWhenNoSensorConfigured() throws Exception {
+ when(mDisplayDeviceConfig.getProximitySensor()).thenReturn(null);
+ when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(
+ TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY));
+
+ mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(
+ mWakelockController, mDisplayDeviceConfig, mTestLooper.getLooper(),
+ mNudgeUpdatePowerState, Display.DEFAULT_DISPLAY,
+ mSensorManager, null);
+ assertFalse(mDisplayPowerProximityStateController.isProximitySensorAvailable());
+ }
+
+ @Test
public void notifyDisplayDeviceChangedReloadsTheProximitySensor() throws Exception {
DisplayDeviceConfig updatedDisplayDeviceConfig = mock(DisplayDeviceConfig.class);
when(updatedDisplayDeviceConfig.getProximitySensor()).thenReturn(
@@ -326,8 +377,8 @@
assertEquals(mDisplayPowerProximityStateController.getPendingProximityDebounceTime(), -1);
}
- private void advanceTime(long timeMs) {
- mClock.fastForward(timeMs);
+ private void advanceTime() {
+ mClock.fastForward(1);
mTestLooper.dispatchAll();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java
new file mode 100644
index 0000000..c02cbd1
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.dreams;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.content.ContextWrapper;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.PowerManagerInternal;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/**
+ * Collection of tests for exercising the {@link DreamManagerService} lifecycle.
+ */
+public class DreamManagerServiceMockingTest {
+ private ContextWrapper mContextSpy;
+ private Resources mResourcesSpy;
+
+ @Mock
+ private ActivityManagerInternal mActivityManagerInternalMock;
+
+ @Mock
+ private PowerManagerInternal mPowerManagerInternalMock;
+
+ @Mock
+ private UserManager mUserManagerMock;
+
+ private MockitoSession mMockitoSession;
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+
+ addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+ addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+
+ when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock);
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(Settings.Secure.class)
+ .startMocking();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mMockitoSession.finishMocking();
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ }
+
+ private DreamManagerService createService() {
+ return new DreamManagerService(mContextSpy);
+ }
+
+ @Test
+ public void testSettingsQueryUserChange() {
+ final DreamManagerService service = createService();
+
+ final SystemService.TargetUser from =
+ new SystemService.TargetUser(mock(UserInfo.class));
+ final SystemService.TargetUser to =
+ new SystemService.TargetUser(mock(UserInfo.class));
+
+ service.onUserSwitching(from, to);
+
+ verify(() -> Settings.Secure.getIntForUser(any(),
+ eq(Settings.Secure.SCREENSAVER_ENABLED),
+ anyInt(),
+ eq(UserHandle.USER_CURRENT)));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index bc5e720..eefe5af 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -31,7 +31,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
-import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
@@ -275,10 +274,10 @@
assertEquals(testUserId, newWallpaperData.userId);
WallpaperData wallpaperData = mService.getWallpaperSafeLocked(testUserId, which);
- assertEquals(wallpaperData.cropFile.getAbsolutePath(),
- newWallpaperData.cropFile.getAbsolutePath());
- assertEquals(wallpaperData.wallpaperFile.getAbsolutePath(),
- newWallpaperData.wallpaperFile.getAbsolutePath());
+ assertEquals(wallpaperData.getCropFile().getAbsolutePath(),
+ newWallpaperData.getCropFile().getAbsolutePath());
+ assertEquals(wallpaperData.getWallpaperFile().getAbsolutePath(),
+ newWallpaperData.getWallpaperFile().getAbsolutePath());
}
}
@@ -525,7 +524,8 @@
@Test
public void getWallpaperWithFeature_getCropped_returnsCropFile() throws Exception {
File cropSystemWallpaperFile =
- new File(WallpaperUtils.getWallpaperDir(USER_SYSTEM), WALLPAPER_CROP);
+ new WallpaperData(USER_SYSTEM, FLAG_SYSTEM).getCropFile();
+ cropSystemWallpaperFile.getParentFile().mkdirs();
cropSystemWallpaperFile.createNewFile();
try (FileOutputStream outputStream = new FileOutputStream(cropSystemWallpaperFile)) {
outputStream.write("Crop system wallpaper".getBytes());
@@ -547,7 +547,8 @@
@Test
public void getWallpaperWithFeature_notGetCropped_returnsOriginalFile() throws Exception {
File originalSystemWallpaperFile =
- new File(WallpaperUtils.getWallpaperDir(USER_SYSTEM), WALLPAPER);
+ new WallpaperData(USER_SYSTEM, FLAG_SYSTEM).getWallpaperFile();
+ originalSystemWallpaperFile.getParentFile().mkdirs();
originalSystemWallpaperFile.createNewFile();
try (FileOutputStream outputStream = new FileOutputStream(originalSystemWallpaperFile)) {
outputStream.write("Original system wallpaper".getBytes());
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 107dde2..fa0a971 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -110,6 +110,7 @@
<uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
+ <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
<queries>
<package android:name="com.android.servicestests.apps.suspendtestapp" />
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
index 88d57ac..e565faa 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
@@ -18,7 +18,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -42,10 +42,10 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
import org.mockito.Mock;
import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -58,7 +58,7 @@
public final MockitoRule mockito = MockitoJUnit.rule();
private Context mContext;
- private AudioSystemAdapter mAudioSystem;
+ private AudioSystemAdapter mSpyAudioSystem;
private SettingsAdapter mSettingsAdapter;
@Spy private NoOpSystemServerAdapter mSpySystemServer;
@@ -78,11 +78,11 @@
sLooperPrepared = true;
}
mContext = InstrumentationRegistry.getTargetContext();
- mAudioSystem = new NoOpAudioSystemAdapter();
+ mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
mSettingsAdapter = new NoOpSettingsAdapter();
when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(AppOpsManager.MODE_ALLOWED);
- mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
+ mAudioService = new AudioService(mContext, mSpyAudioSystem, mSpySystemServer,
mSettingsAdapter, mMockAudioPolicy, null, mMockAppOpsManager,
mMockPermissionEnforcer);
}
@@ -95,7 +95,7 @@
public void testMuteMicrophone() throws Exception {
Log.i(TAG, "running testMuteMicrophone");
Assert.assertNotNull(mAudioService);
- final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mAudioSystem;
+ final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mSpyAudioSystem;
testAudioSystem.configureMuteMicrophoneToFail(false);
for (boolean muted : new boolean[] { true, false}) {
testAudioSystem.configureIsMicrophoneMuted(!muted);
@@ -120,7 +120,7 @@
public void testMuteMicrophoneWhenFail() throws Exception {
Log.i(TAG, "running testMuteMicrophoneWhenFail");
Assert.assertNotNull(mAudioService);
- final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mAudioSystem;
+ final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mSpyAudioSystem;
testAudioSystem.configureMuteMicrophoneToFail(true);
for (boolean muted : new boolean[] { true, false}) {
testAudioSystem.configureIsMicrophoneMuted(!muted);
@@ -175,4 +175,28 @@
Assert.assertEquals(false, mAudioService.isHotwordStreamSupported(false));
Assert.assertEquals(false, mAudioService.isHotwordStreamSupported(true));
}
+
+ /**
+ * Test master mute setter and getter
+ */
+ @Test
+ public void testMasterMute() throws Exception {
+ Log.i(TAG, "running testMasterMute");
+ Assert.assertNotNull(mAudioService);
+ for (boolean mute : new boolean[] { true, false}) {
+ boolean wasMute = mAudioService.isMasterMute();
+ mAudioService.setMasterMute(mute, 0 /* flags */, mContext.getOpPackageName(),
+ UserHandle.getCallingUserId(), null);
+
+ Assert.assertEquals("master mute reporting wrong value",
+ mute, mAudioService.isMasterMute());
+
+ verify(mSpyAudioSystem, times(wasMute == mute ? 0 : 1)).setMasterMute(mute);
+ // verify the intent for master mute changed is supposed to be fired
+ verify(mSpySystemServer,
+ after(MAX_MESSAGE_HANDLING_DELAY_MS).times(wasMute == mute ? 0 : 1))
+ .broadcastMasterMuteStatus(mute);
+ reset(mSpySystemServer);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 08a0878..0eac718 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -142,4 +142,9 @@
@NonNull AudioAttributes attributes, boolean forVolume) {
return new ArrayList<>();
}
+
+ @Override
+ public int setMasterMute(boolean muted) {
+ return AudioSystem.AUDIO_STATUS_OK;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpSystemServerAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpSystemServerAdapter.java
index 83c5663..a715f51 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpSystemServerAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpSystemServerAdapter.java
@@ -39,4 +39,9 @@
public void sendDeviceBecomingNoisyIntent() {
// no-op
}
+
+ @Override
+ public void broadcastMasterMuteStatus(boolean muted) {
+ // no-op
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 67be376..41f7dbc 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -18,7 +18,6 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
@@ -183,6 +182,10 @@
.thenReturn(ERROR_HW_UNAVAILABLE);
when(mResources.getString(R.string.biometric_not_recognized))
.thenReturn(ERROR_NOT_RECOGNIZED);
+ when(mResources.getString(R.string.biometric_face_not_recognized))
+ .thenReturn(ERROR_NOT_RECOGNIZED);
+ when(mResources.getString(R.string.fingerprint_error_not_match))
+ .thenReturn(ERROR_NOT_RECOGNIZED);
when(mResources.getString(R.string.biometric_error_user_canceled))
.thenReturn(ERROR_USER_CANCELED);
@@ -903,6 +906,45 @@
}
@Test
+ public void testMultiBiometricAuth_whenLockoutTimed_sendsErrorAndModality()
+ throws Exception {
+ testMultiBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_TIMED,
+ BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT);
+ }
+
+ @Test
+ public void testMultiBiometricAuth_whenLockoutPermanent_sendsErrorAndModality()
+ throws Exception {
+ testMultiBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_PERMANENT,
+ BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
+ }
+
+ private void testMultiBiometricAuth_whenLockout(@LockoutTracker.LockoutMode int lockoutMode,
+ int biometricPromptError) throws Exception {
+ final int[] modalities = new int[] {
+ TYPE_FINGERPRINT,
+ BiometricAuthenticator.TYPE_FACE,
+ };
+
+ final int[] strengths = new int[] {
+ Authenticators.BIOMETRIC_STRONG,
+ Authenticators.BIOMETRIC_STRONG,
+ };
+ setupAuthForMultiple(modalities, strengths);
+
+ when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
+ .thenReturn(lockoutMode);
+ when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */, null /* authenticators */);
+ waitForIdle();
+
+ // The lockout error should be sent, instead of ERROR_NONE_ENROLLED. See b/286923477.
+ verify(mReceiver1).onError(eq(TYPE_FINGERPRINT),
+ eq(biometricPromptError), eq(0) /* vendorCode */);
+ }
+
+ @Test
public void testBiometricOrCredentialAuth_whenBiometricLockout_showsCredential()
throws Exception {
when(mTrustManager.isDeviceSecure(anyInt(), anyInt())).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index e9d8269..8929900 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -19,6 +19,8 @@
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -405,6 +407,59 @@
testCancelsEnrollWhenRequestId(10L, 20, false /* started */);
}
+ @Test
+ public void testCancelAuthenticationClientWithoutStarting() {
+ final Supplier<Object> lazyDaemon = () -> mock(Object.class);
+ final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon);
+ final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+ final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon,
+ mToken, callback, mBiometricContext);
+
+ //Schedule authentication client to the pending queue
+ mScheduler.scheduleClientMonitor(client1);
+ mScheduler.scheduleClientMonitor(client2);
+ waitForIdle();
+
+ assertThat(mScheduler.getCurrentClient()).isEqualTo(client1);
+
+ client2.cancel();
+ waitForIdle();
+
+ assertThat(client2.isAlreadyCancelled()).isTrue();
+
+ client1.getCallback().onClientFinished(client1, false);
+ waitForIdle();
+
+ assertThat(mScheduler.getCurrentClient()).isNull();
+ }
+
+ @Test
+ public void testCancelAuthenticationClientWithoutStarting_whenAppCrashes() {
+ final Supplier<Object> lazyDaemon = () -> mock(Object.class);
+ final TestHalClientMonitor client1 = new TestHalClientMonitor(mContext, mToken, lazyDaemon);
+ final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+ final TestAuthenticationClient client2 = new TestAuthenticationClient(mContext, lazyDaemon,
+ mToken, callback, mBiometricContext);
+
+ //Schedule authentication client to the pending queue
+ mScheduler.scheduleClientMonitor(client1);
+ mScheduler.scheduleClientMonitor(client2);
+ waitForIdle();
+
+ assertThat(mScheduler.getCurrentClient()).isEqualTo(client1);
+
+ //App crashes
+ client2.binderDied();
+ waitForIdle();
+
+ assertThat(client2.isAlreadyCancelled()).isTrue();
+
+ client1.getCallback().onClientFinished(client1, false);
+ waitForIdle();
+
+ assertThat(mScheduler.getCurrentClient()).isNull();
+ }
+
private void testCancelsEnrollWhenRequestId(@Nullable Long requestId, long cancelRequestId,
boolean started) {
final Supplier<Object> lazyDaemon = () -> mock(Object.class);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index 359d711..046b01c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -152,6 +152,28 @@
}
@Test
+ public void testLockoutEndsOperation() throws RemoteException {
+ final FaceAuthenticationClient client = createClient(2);
+ client.start(mCallback);
+ client.onLockoutPermanent();
+
+ verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
+ eq(FACE_ERROR_LOCKOUT_PERMANENT), anyInt());
+ verify(mCallback).onClientFinished(client, false);
+ }
+
+ @Test
+ public void testTemporaryLockoutEndsOperation() throws RemoteException {
+ final FaceAuthenticationClient client = createClient(2);
+ client.start(mCallback);
+ client.onLockoutTimed(1000);
+
+ verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
+ eq(FACE_ERROR_LOCKOUT), anyInt());
+ verify(mCallback).onClientFinished(client, false);
+ }
+
+ @Test
public void notifyHalWhenContextChanges() throws RemoteException {
final FaceAuthenticationClient client = createClient();
client.start(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index 31a58cd..d1d6e9d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -36,7 +36,6 @@
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
-import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -73,7 +72,7 @@
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
- private TestableFaceProvider mFaceProvider;
+ private FaceProvider mFaceProvider;
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -98,8 +97,9 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFaceProvider = new TestableFaceProvider(mDaemon, mContext, mBiometricStateCallback,
- mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext);
+ mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback,
+ mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext,
+ mDaemon);
}
@Test
@@ -130,6 +130,7 @@
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId).getScheduler();
+ scheduler.reset();
for (int i = 0; i < numFakeOperations; i++) {
final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
@@ -142,7 +143,7 @@
for (SensorProps prop : mSensorProps) {
final BiometricScheduler scheduler =
mFaceProvider.mFaceSensors.get(prop.commonProps.sensorId).getScheduler();
- assertEquals(numFakeOperations, scheduler.getCurrentPendingCount());
+ assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
assertNotNull(scheduler.getCurrentClient());
}
@@ -159,25 +160,4 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
-
- private static class TestableFaceProvider extends FaceProvider {
- private final IFace mDaemon;
-
- TestableFaceProvider(@NonNull IFace daemon,
- @NonNull Context context,
- @NonNull BiometricStateCallback biometricStateCallback,
- @NonNull SensorProps[] props,
- @NonNull String halInstanceName,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- biometricContext);
- mDaemon = daemon;
- }
-
- @Override
- synchronized IFace getHalInstance() {
- return mDaemon;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 9c01de6..8f6efff 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -39,7 +39,6 @@
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
-import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -81,7 +80,7 @@
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
- private TestableFingerprintProvider mFingerprintProvider;
+ private FingerprintProvider mFingerprintProvider;
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -110,17 +109,13 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext,
+ mFingerprintProvider = new FingerprintProvider(mContext,
mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext);
+ mGestureAvailabilityDispatcher, mBiometricContext, mDaemon);
}
@Test
public void testAddingSensors() {
- mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext,
- mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext);
-
waitForIdle();
for (SensorProps prop : mSensorProps) {
@@ -147,6 +142,7 @@
final BiometricScheduler scheduler =
mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
.getScheduler();
+ scheduler.reset();
for (int i = 0; i < numFakeOperations; i++) {
final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
when(testMonitor.getFreshDaemon()).thenReturn(new Object());
@@ -160,7 +156,7 @@
final BiometricScheduler scheduler =
mFingerprintProvider.mFingerprintSensors.get(prop.commonProps.sensorId)
.getScheduler();
- assertEquals(numFakeOperations, scheduler.getCurrentPendingCount());
+ assertEquals(numFakeOperations - 1, scheduler.getCurrentPendingCount());
assertNotNull(scheduler.getCurrentClient());
}
@@ -178,26 +174,4 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
-
- private static class TestableFingerprintProvider extends FingerprintProvider {
- private final IFingerprint mDaemon;
-
- TestableFingerprintProvider(@NonNull IFingerprint daemon,
- @NonNull Context context,
- @NonNull BiometricStateCallback biometricStateCallback,
- @NonNull SensorProps[] props,
- @NonNull String halInstanceName,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- @NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext);
- mDaemon = daemon;
- }
-
- @Override
- synchronized IFingerprint getHalInstance() {
- return mDaemon;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
index dccc26a..7b5c57f 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
@@ -35,6 +35,7 @@
final byte[] appIcon = "appIcon".getBytes();
final String appName = "appName";
final String appIdentifier = "com.google.test";
+ final String extendedId = "com.google.test/.InCallService";
final int status = 1;
final int direction = android.companion.Telecom.Call.OUTGOING;
final int control1 = 2;
@@ -43,7 +44,7 @@
call.setCallerId(callerId);
call.setAppIcon(appIcon);
final CallMetadataSyncData.CallFacilitator callFacilitator =
- new CallMetadataSyncData.CallFacilitator(appName, appIdentifier);
+ new CallMetadataSyncData.CallFacilitator(appName, appIdentifier, extendedId);
call.setFacilitator(callFacilitator);
call.setStatus(status);
call.setDirection(direction);
@@ -59,6 +60,8 @@
assertThat(reconstructedCall.getAppIcon()).isEqualTo(appIcon);
assertThat(reconstructedCall.getFacilitator().getName()).isEqualTo(appName);
assertThat(reconstructedCall.getFacilitator().getIdentifier()).isEqualTo(appIdentifier);
+ assertThat(reconstructedCall.getFacilitator().getExtendedIdentifier())
+ .isEqualTo(extendedId);
assertThat(reconstructedCall.getStatus()).isEqualTo(status);
assertThat(reconstructedCall.getDirection()).isEqualTo(direction);
assertThat(reconstructedCall.getControls()).containsExactly(control1, control2);
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
index 201d8f9..a13cc41 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
@@ -308,6 +308,18 @@
.isEqualTo(CONTACT_DISPLAY_NAME);
}
+ @Test
+ public void getSerializedPhoneAccountHandle_serializesCorrectly() {
+ final CrossDeviceCall crossDeviceCall = new CrossDeviceCall(
+ InstrumentationRegistry.getTargetContext(),
+ mUninitializedCallDetails, /* callAudioState= */ null);
+
+ final String result = crossDeviceCall.getSerializedPhoneAccountHandle();
+
+ assertWithMessage("Wrong phone account handle serialization").that(result)
+ .isEqualTo("label::com.google.test/com.google.test.Activity");
+ }
+
private Call.Details createCallDetails(int state, int capabilities) {
return createCallDetails(state, capabilities, /* hasContactName= */ true);
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
index 7e392a4..e6cc343 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
@@ -195,7 +195,8 @@
new CrossDeviceSyncController.PhoneAccountManager(mMockContext);
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addFacilitator(
- new CallMetadataSyncData.CallFacilitator("name", "com.google.test"));
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
phoneAccountManager.updateFacilitators(0, callMetadataSyncData);
phoneAccountManager.updateFacilitators(0, callMetadataSyncData);
verify(mMockTelecomManager, times(1)).registerPhoneAccount(any());
@@ -208,10 +209,12 @@
new CrossDeviceSyncController.PhoneAccountManager(mMockContext);
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addFacilitator(
- new CallMetadataSyncData.CallFacilitator("name", "com.google.test"));
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
phoneAccountManager.updateFacilitators(0, callMetadataSyncData);
callMetadataSyncData.addFacilitator(
- new CallMetadataSyncData.CallFacilitator("name", "com.google.test2"));
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test2",
+ "com.google.test2/.InCallService"));
phoneAccountManager.updateFacilitators(0, callMetadataSyncData);
verify(mMockTelecomManager, times(2)).registerPhoneAccount(any());
verify(mMockTelecomManager, times(0)).unregisterPhoneAccount(any());
@@ -223,7 +226,8 @@
new CrossDeviceSyncController.PhoneAccountManager(mMockContext);
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addFacilitator(
- new CallMetadataSyncData.CallFacilitator("name", "com.google.test"));
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
phoneAccountManager.updateFacilitators(0, callMetadataSyncData);
final CallMetadataSyncData callMetadataSyncData2 = new CallMetadataSyncData();
phoneAccountManager.updateFacilitators(0, callMetadataSyncData2);
@@ -236,7 +240,9 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc");
call.setDirection(android.companion.Telecom.Call.INCOMING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
final CrossDeviceSyncController.CallManager callManager =
@@ -252,7 +258,9 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc");
call.setDirection(android.companion.Telecom.Call.OUTGOING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
call.setCallerId("555-555-5555");
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
@@ -269,7 +277,9 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc");
call.setDirection(android.companion.Telecom.Call.OUTGOING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(
+ new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
final CrossDeviceSyncController.CallManager callManager =
@@ -316,7 +326,8 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc::originalId");
call.setDirection(android.companion.Telecom.Call.INCOMING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
final CrossDeviceSyncController.CallManager callManager =
@@ -334,7 +345,8 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc::originalId");
call.setDirection(android.companion.Telecom.Call.OUTGOING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
call.setCallerId("555-555-5555");
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
@@ -352,7 +364,8 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc");
call.setDirection(android.companion.Telecom.Call.INCOMING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
final CrossDeviceSyncController.CallManager callManager =
@@ -369,7 +382,8 @@
final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
call.setId("123abc");
call.setDirection(android.companion.Telecom.Call.OUTGOING);
- call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.android.test"));
+ call.setFacilitator(new CallMetadataSyncData.CallFacilitator("name", "com.google.test",
+ "com.google.test/.InCallService"));
call.setCallerId("555-555-5555");
final CallMetadataSyncData callMetadataSyncData = new CallMetadataSyncData();
callMetadataSyncData.addCall(call);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 379c8b7..4b801bc 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.companion.virtual;
+import static android.companion.virtual.VirtualDeviceManager.ASSOCIATION_ID_INVALID;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
@@ -1711,6 +1712,22 @@
assertThat(displayIds).containsExactly(DISPLAY_ID_1, DISPLAY_ID_2);
}
+ @Test
+ public void getAssociationIdForDevice_invalidDeviceId_returnsInvalidAssociationId() {
+ assertThat(mLocalService.getAssociationIdForDevice(DEVICE_ID_INVALID))
+ .isEqualTo(ASSOCIATION_ID_INVALID);
+ assertThat(mLocalService.getAssociationIdForDevice(DEVICE_ID_DEFAULT))
+ .isEqualTo(ASSOCIATION_ID_INVALID);
+ assertThat(mLocalService.getAssociationIdForDevice(VIRTUAL_DEVICE_ID_2))
+ .isEqualTo(ASSOCIATION_ID_INVALID);
+ }
+
+ @Test
+ public void getAssociationIdForDevice_returnsCorrectAssociationId() {
+ assertThat(mLocalService.getAssociationIdForDevice(VIRTUAL_DEVICE_ID_1))
+ .isEqualTo(mAssociationInfo.getId());
+ }
+
private VirtualDeviceImpl createVirtualDevice(int virtualDeviceId, int ownerUid) {
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
.setBlockedActivities(getBlockedActivities())
@@ -1727,6 +1744,7 @@
mPendingTrampolineCallback, mActivityListener, mSoundEffectListener,
mRunningAppsChangedCallback, params, new DisplayManagerGlobal(mIDisplayManager));
mVdms.addVirtualDevice(virtualDeviceImpl);
+ assertThat(virtualDeviceImpl.getAssociationId()).isEqualTo(mAssociationInfo.getId());
return virtualDeviceImpl;
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index a2e204d..28df24c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -37,34 +37,36 @@
public class VirtualDeviceTest {
private static final int VIRTUAL_DEVICE_ID = 42;
- private static final String VIRTUAL_DEVICE_NAME = "VirtualDeviceName";
+ private static final String PERSISTENT_ID = "persistentId";
+ private static final String DEVICE_NAME = "VirtualDeviceName";
@Test
public void build_invalidId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(DEVICE_ID_INVALID, VIRTUAL_DEVICE_NAME));
+ () -> new VirtualDevice(DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
}
@Test
public void build_defaultId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(DEVICE_ID_DEFAULT, VIRTUAL_DEVICE_NAME));
+ () -> new VirtualDevice(DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
}
@Test
- public void build_nameIsOptional() {
+ public void build_onlyRequiredFields() {
VirtualDevice virtualDevice =
- new VirtualDevice(VIRTUAL_DEVICE_ID, /* name= */ null);
+ new VirtualDevice(VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
assertThat(virtualDevice.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
+ assertThat(virtualDevice.getPersistentDeviceId()).isNull();
assertThat(virtualDevice.getName()).isNull();
}
@Test
public void parcelable_shouldRecreateSuccessfully() {
VirtualDevice originalDevice =
- new VirtualDevice(VIRTUAL_DEVICE_ID, VIRTUAL_DEVICE_NAME);
+ new VirtualDevice(VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
Parcel parcel = Parcel.obtain();
originalDevice.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
@@ -72,6 +74,7 @@
VirtualDevice device = VirtualDevice.CREATOR.createFromParcel(parcel);
assertThat(device).isEqualTo(originalDevice);
assertThat(device.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
- assertThat(device.getName()).isEqualTo(VIRTUAL_DEVICE_NAME);
+ assertThat(device.getPersistentDeviceId()).isEqualTo(PERSISTENT_ID);
+ assertThat(device.getName()).isEqualTo(DEVICE_NAME);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 708421d..8b04eca 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -33,8 +33,8 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.server.display.config.ThermalStatus;
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 0e775d5..5db9d1f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -60,6 +61,8 @@
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
@@ -109,8 +112,6 @@
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-import com.google.common.collect.ImmutableMap;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -125,6 +126,7 @@
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -136,6 +138,9 @@
public class DisplayManagerServiceTest {
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
+
+ private static final float FLOAT_TOLERANCE = 0.01f;
+
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
private static final long STANDARD_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
@@ -250,6 +255,10 @@
@Mock IBinder mMockDisplayToken;
@Mock SensorManagerInternal mMockSensorManagerInternal;
+ @Mock SensorManager mSensorManager;
+
+ @Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
+
@Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
@Before
@@ -267,7 +276,7 @@
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
LocalServices.addService(
VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
-
+ // TODO: b/287945043
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
VirtualDeviceManager vdm = new VirtualDeviceManager(mIVirtualDeviceManager, mContext);
@@ -396,7 +405,7 @@
final int size = displayIds.length;
assertTrue(size > 0);
- Map<Integer, Integer> expectedDisplayTypeToViewPortTypeMapping = ImmutableMap.of(
+ Map<Integer, Integer> expectedDisplayTypeToViewPortTypeMapping = Map.of(
Display.TYPE_INTERNAL, DisplayViewport.VIEWPORT_INTERNAL,
Display.TYPE_EXTERNAL, DisplayViewport.VIEWPORT_EXTERNAL
);
@@ -1934,6 +1943,74 @@
assertEquals(mode, displayManager.getHdrConversionModeInternal());
}
+ @Test
+ public void testReturnsRefreshRateForDisplayAndSensor_proximitySensorSet() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerInternal localService = displayManager.new LocalService();
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ displayManager.overrideSensorManager(mSensorManager);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+
+ String testSensorName = "testName";
+ String testSensorType = "testType";
+ Sensor testSensor = TestUtils.createSensor(testSensorType, testSensorName);
+
+ DisplayDeviceConfig.SensorData sensorData = new DisplayDeviceConfig.SensorData();
+ sensorData.type = testSensorType;
+ sensorData.name = testSensorName;
+ sensorData.minRefreshRate = 10f;
+ sensorData.maxRefreshRate = 100f;
+
+ when(mMockDisplayDeviceConfig.getProximitySensor()).thenReturn(sensorData);
+ when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(Collections.singletonList(
+ testSensor));
+
+ SurfaceControl.RefreshRateRange result = localService.getRefreshRateForDisplayAndSensor(
+ displayId, testSensorName, testSensorType);
+
+ assertNotNull(result);
+ assertEquals(result.min, sensorData.minRefreshRate, FLOAT_TOLERANCE);
+ assertEquals(result.max, sensorData.maxRefreshRate, FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testReturnsRefreshRateForDisplayAndSensor_proximitySensorNotSet() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerInternal localService = displayManager.new LocalService();
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ displayManager.overrideSensorManager(mSensorManager);
+
+ FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+ displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+ int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+ displayDevice);
+
+ String testSensorName = "testName";
+ String testSensorType = "testType";
+ Sensor testSensor = TestUtils.createSensor(testSensorType, testSensorName);
+
+ DisplayDeviceConfig.SensorData sensorData = new DisplayDeviceConfig.SensorData();
+ sensorData.type = testSensorType;
+ sensorData.name = testSensorName;
+ sensorData.minRefreshRate = 10f;
+ sensorData.maxRefreshRate = 100f;
+
+ when(mMockDisplayDeviceConfig.getProximitySensor()).thenReturn(null);
+ when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(Collections.singletonList(
+ testSensor));
+
+ SurfaceControl.RefreshRateRange result = localService.getRefreshRateForDisplayAndSensor(
+ displayId, testSensorName, testSensorType);
+
+ assertNull(result);
+ }
+
private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
throws Exception {
DisplayManagerService displayManager =
diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
index 90d9bae..8b45145 100644
--- a/services/tests/servicestests/src/com/android/server/display/TestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
@@ -18,6 +18,7 @@
import android.hardware.Sensor;
import android.hardware.SensorEvent;
+import android.hardware.input.InputSensorInfo;
import android.os.Parcel;
import android.os.SystemClock;
import android.view.DisplayAddress;
@@ -75,6 +76,12 @@
return sensor;
}
+ public static Sensor createSensor(String type, String name) {
+ return new Sensor(new InputSensorInfo(
+ name, "vendor", 0, 0, 0, 1f, 1f, 1, 1, 1, 1,
+ type, "", 0, 0, 0));
+ }
+
/**
* Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
* display-address implementation in our code. Intentionally uses default object (reference)
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index d9cf15b..b652576 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -96,32 +96,101 @@
}
@Test
- public void setAutoBrightnessWhenDisabled() {
+ public void testAutoBrightnessState_AutoBrightnessDisabled() {
mAutomaticBrightnessStrategy.setUseAutoBrightness(false);
int targetDisplayState = Display.STATE_ON;
boolean allowAutoBrightnessWhileDozing = false;
- float brightnessState = Float.NaN;
- int brightnessReason = BrightnessReason.REASON_OVERRIDE;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
float lastUserSetBrightness = 0.2f;
boolean userSetBrightnessChanged = true;
mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true);
mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
- allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy,
- lastUserSetBrightness, userSetBrightnessChanged);
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
verify(mAutomaticBrightnessController)
.configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
mBrightnessConfiguration,
lastUserSetBrightness,
userSetBrightnessChanged, 0.5f,
false, policy, true);
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
}
@Test
- public void setAutoBrightnessWhenEnabledAndDisplayIsDozing() {
+ public void testAutoBrightnessState_DisplayIsOff() {
+ mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+ int targetDisplayState = Display.STATE_OFF;
+ boolean allowAutoBrightnessWhileDozing = false;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+ int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+ float lastUserSetBrightness = 0.2f;
+ boolean userSetBrightnessChanged = true;
+ mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true);
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController)
+ .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ mBrightnessConfiguration,
+ lastUserSetBrightness,
+ userSetBrightnessChanged, 0.5f,
+ false, policy, true);
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+ }
+
+ @Test
+ public void testAutoBrightnessState_DisplayIsInDoze_ConfigDoesNotAllow() {
mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
int targetDisplayState = Display.STATE_DOZE;
- float brightnessState = Float.NaN;
+ boolean allowAutoBrightnessWhileDozing = false;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+ int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+ float lastUserSetBrightness = 0.2f;
+ boolean userSetBrightnessChanged = true;
+ mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true);
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController)
+ .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+ mBrightnessConfiguration,
+ lastUserSetBrightness,
+ userSetBrightnessChanged, 0.5f,
+ false, policy, true);
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+ }
+
+ @Test
+ public void testAutoBrightnessState_BrightnessReasonIsOverride() {
+ mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+ int targetDisplayState = Display.STATE_ON;
+ boolean allowAutoBrightnessWhileDozing = false;
+ int brightnessReason = BrightnessReason.REASON_OVERRIDE;
+ int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+ float lastUserSetBrightness = 0.2f;
+ boolean userSetBrightnessChanged = true;
+ mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true);
+ mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
+ verify(mAutomaticBrightnessController)
+ .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+ mBrightnessConfiguration,
+ lastUserSetBrightness,
+ userSetBrightnessChanged, 0.5f,
+ false, policy, true);
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+ }
+
+ @Test
+ public void testAutoBrightnessState_DisplayIsInDoze_ConfigDoesAllow() {
+ mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+ int targetDisplayState = Display.STATE_DOZE;
boolean allowAutoBrightnessWhileDozing = true;
int brightnessReason = BrightnessReason.REASON_DOZE;
int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
@@ -131,23 +200,24 @@
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.4f);
mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(false);
mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
- allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy,
- lastUserSetBrightness, userSetBrightnessChanged);
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
verify(mAutomaticBrightnessController)
.configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
mBrightnessConfiguration,
lastUserSetBrightness,
userSetBrightnessChanged, 0.4f,
true, policy, true);
+ assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
}
@Test
- public void setAutoBrightnessWhenEnabledAndDisplayIsOn() {
+ public void testAutoBrightnessState_DisplayIsOn() {
mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
int targetDisplayState = Display.STATE_ON;
- float brightnessState = Float.NaN;
boolean allowAutoBrightnessWhileDozing = false;
- int brightnessReason = BrightnessReason.REASON_OVERRIDE;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
float lastUserSetBrightness = 0.2f;
boolean userSetBrightnessChanged = true;
int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
@@ -156,14 +226,16 @@
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment);
mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(false);
mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
- allowAutoBrightnessWhileDozing, brightnessState, brightnessReason, policy,
- lastUserSetBrightness, userSetBrightnessChanged);
+ allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+ userSetBrightnessChanged);
verify(mAutomaticBrightnessController)
.configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
mBrightnessConfiguration,
lastUserSetBrightness,
userSetBrightnessChanged, pendingBrightnessAdjustment,
true, policy, true);
+ assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+ assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
}
@Test
@@ -210,7 +282,6 @@
when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()).thenReturn(
autoBrightnessAdjustment);
mAutomaticBrightnessStrategy.adjustAutomaticBrightnessStateIfValid(brightnessState);
- assertTrue(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness());
assertEquals(autoBrightnessAdjustment,
mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
assertEquals(autoBrightnessAdjustment, Settings.System.getFloatForUser(
@@ -222,7 +293,6 @@
float invalidBrightness = -0.5f;
mAutomaticBrightnessStrategy
.adjustAutomaticBrightnessStateIfValid(invalidBrightness);
- assertFalse(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness());
assertEquals(autoBrightnessAdjustment,
mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
assertEquals(0,
diff --git a/services/tests/servicestests/src/com/android/server/display/utils/SensorUtilsTest.java b/services/tests/servicestests/src/com/android/server/display/utils/SensorUtilsTest.java
new file mode 100644
index 0000000..4494b0c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/utils/SensorUtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.input.InputSensorInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.display.DisplayDeviceConfig.SensorData;
+
+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;
+import java.util.List;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class SensorUtilsTest {
+
+ private static final String TEST_SENSOR_NAME = "test_sensor_name";
+ private static final String TEST_SENSOR_TYPE = "test_sensor_type";
+ private static final Sensor TEST_SENSOR = createSensor();
+ @Mock
+ private SensorManager mSensorManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testNoSensorData() {
+ Sensor result = SensorUtils.findSensor(mSensorManager, null, Sensor.TYPE_LIGHT);
+ assertNull(result);
+ }
+
+ @Test
+ public void testNoSensorManager() {
+ Sensor result = SensorUtils.findSensor(null, new SensorData(), Sensor.TYPE_LIGHT);
+ assertNull(result);
+ }
+
+ @Keep
+ private static Object[][] findSensorData() {
+ // sensorName, sensorType, fallbackType, allSensors, defaultSensor, expectedResult
+ return new Object[][]{
+ // no data, no default
+ {null, null, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // matching name, matching type, no default
+ {TEST_SENSOR_NAME, TEST_SENSOR_TYPE, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, TEST_SENSOR},
+ // matching name, no default
+ {TEST_SENSOR_NAME, null, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, TEST_SENSOR},
+ // not matching name, no default
+ {"not_matching_name", null, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // matching type, no default
+ {null, TEST_SENSOR_TYPE, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, TEST_SENSOR},
+ // not matching type, no default
+ {null, "not_matching_type", Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // not matching type, matching name, no default
+ {TEST_SENSOR_NAME, "not_matching_type", Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // not matching name, matching type, no default
+ {"not_matching_name", TEST_SENSOR_TYPE, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // not matching type, not matching name, no default
+ {"not_matching_name", "not_matching_type", Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), null, null},
+ // not matching type, not matching name, with default
+ {"not_matching_name", "not_matching_type", Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), TEST_SENSOR, TEST_SENSOR},
+ // no data, with default
+ {null, null, Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), TEST_SENSOR, TEST_SENSOR},
+ // empty data, with default
+ {"", "", Sensor.TYPE_LIGHT,
+ Collections.singletonList(TEST_SENSOR), TEST_SENSOR, TEST_SENSOR},
+ // empty data, with default, no fallback
+ {"", "", SensorUtils.NO_FALLBACK,
+ Collections.singletonList(TEST_SENSOR), TEST_SENSOR, null},
+ };
+ }
+
+ @Test
+ @Parameters(method = "findSensorData")
+ public void testFindSensor(@Nullable String sensorName, @Nullable String sensorType,
+ int fallbackType, List<Sensor> allSensors, @Nullable Sensor defaultSensor,
+ @Nullable Sensor expectedResult) {
+ when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(allSensors);
+ when(mSensorManager.getDefaultSensor(fallbackType)).thenReturn(defaultSensor);
+
+ SensorData sensorData = new SensorData();
+ sensorData.name = sensorName;
+ sensorData.type = sensorType;
+
+ Sensor result = SensorUtils.findSensor(mSensorManager, sensorData, fallbackType);
+
+ assertEquals(expectedResult, result);
+ }
+
+ private static Sensor createSensor() {
+ return new Sensor(new InputSensorInfo(
+ TEST_SENSOR_NAME, "vendor", 0, 0, 0, 1f, 1f, 1, 1, 1, 1,
+ TEST_SENSOR_TYPE, "", 0, 0, 0));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
index 5070b08..68ef80f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
@@ -118,6 +118,11 @@
boolean isPowerStandbyOrTransient() {
return false;
}
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
};
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
index 49023c6..26b448a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
@@ -127,6 +127,11 @@
boolean isPowerStandbyOrTransient() {
return false;
}
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
};
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index 5e54d3b..ffe088c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -76,6 +76,8 @@
private TestLooper mTestLooper = new TestLooper();
private int mPhysicalAddress = 0x1110;
private HdmiPortInfo[] mHdmiPortInfo;
+ private HdmiEarcController mHdmiEarcController;
+ private FakeEarcNativeWrapper mEarcNativeWrapper;
@Before
public void setUp() throws RemoteException {
@@ -94,7 +96,6 @@
doNothing().when(mHdmiControlServiceSpy)
.writeStringSystemProperty(anyString(), anyString());
doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter();
-
HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
doReturn(hdmiCecConfig).when(mHdmiControlServiceSpy).getHdmiCecConfig();
@@ -118,6 +119,11 @@
mHdmiControlServiceSpy.setHdmiCecNetwork(mHdmiCecNetwork);
mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
+ mEarcNativeWrapper = new FakeEarcNativeWrapper();
+ mHdmiEarcController = HdmiEarcController.createWithNativeWrapper(
+ mHdmiControlServiceSpy, mEarcNativeWrapper);
+ mHdmiControlServiceSpy.setEarcController(mHdmiEarcController);
+
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTvTest.java
new file mode 100644
index 0000000..2405757
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTvTest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.hdmi;
+
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING;
+import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_UNKNOWN;
+import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.stats.hdmi.HdmiStatsEnums;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.SystemService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+
+/**
+ * Tests for the {@link HdmiCecAtomWriter} class and its usage by the HDMI-CEC framework.
+ */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class HdmiCecAtomLoggingTvTest {
+ private HdmiCecAtomWriter mHdmiCecAtomWriterSpy;
+ private HdmiControlService mHdmiControlServiceSpy;
+ private HdmiCecController mHdmiCecController;
+ private HdmiMhlControllerStub mHdmiMhlControllerStub;
+ private FakeNativeWrapper mNativeWrapper;
+ private FakePowerManagerWrapper mPowerManager;
+ private HdmiCecNetwork mHdmiCecNetwork;
+ private Looper mLooper;
+ private Context mContextSpy;
+ private TestLooper mTestLooper = new TestLooper();
+ private int mPhysicalAddress = 0x0000;
+ private static final int EARC_PORT_ID = 1;
+ private HdmiEarcController mHdmiEarcController;
+ private FakeEarcNativeWrapper mEarcNativeWrapper;
+
+ @Before
+ public void setUp() throws RemoteException {
+ mHdmiCecAtomWriterSpy = spy(new HdmiCecAtomWriter());
+
+ mLooper = mTestLooper.getLooper();
+
+ mContextSpy = spy(new ContextWrapper(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()));
+
+ FakeAudioFramework audioFramework = new FakeAudioFramework();
+
+ mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy,
+ Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
+ audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()));
+ doNothing().when(mHdmiControlServiceSpy)
+ .writeStringSystemProperty(anyString(), anyString());
+ doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter();
+
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+ doReturn(hdmiCecConfig).when(mHdmiControlServiceSpy).getHdmiCecConfig();
+
+ mHdmiControlServiceSpy.setIoLooper(mLooper);
+ mHdmiControlServiceSpy.setCecMessageBuffer(
+ new CecMessageBuffer(mHdmiControlServiceSpy));
+
+ mNativeWrapper = new FakeNativeWrapper();
+ mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
+
+ mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+ mHdmiControlServiceSpy, mNativeWrapper, mHdmiCecAtomWriterSpy);
+ mHdmiControlServiceSpy.setCecController(mHdmiCecController);
+
+ mHdmiMhlControllerStub = HdmiMhlControllerStub.create(mHdmiControlServiceSpy);
+ mHdmiControlServiceSpy.setHdmiMhlController(
+ mHdmiMhlControllerStub);
+
+ mHdmiCecNetwork = new HdmiCecNetwork(mHdmiControlServiceSpy,
+ mHdmiCecController, mHdmiMhlControllerStub);
+ mHdmiControlServiceSpy.setHdmiCecNetwork(mHdmiCecNetwork);
+ mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
+
+ mEarcNativeWrapper = new FakeEarcNativeWrapper();
+ mHdmiEarcController = HdmiEarcController.createWithNativeWrapper(
+ mHdmiControlServiceSpy, mEarcNativeWrapper);
+ mHdmiControlServiceSpy.setEarcController(mHdmiEarcController);
+
+ HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
+ hdmiPortInfos[0] =
+ new HdmiPortInfo.Builder(EARC_PORT_ID, HdmiPortInfo.PORT_OUTPUT, 0x0000)
+ .setCecSupported(true)
+ .setMhlSupported(false)
+ .setArcSupported(false)
+ .setEarcSupported(true)
+ .build();
+ mNativeWrapper.setPortInfo(hdmiPortInfos);
+ mNativeWrapper.setPortConnectionStatus(EARC_PORT_ID, true);
+
+ mHdmiControlServiceSpy.initService();
+ mPowerManager = new FakePowerManagerWrapper(mContextSpy);
+ mHdmiControlServiceSpy.setPowerManager(mPowerManager);
+ mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
+ mTestLooper.dispatchAll();
+
+ Mockito.reset(mHdmiCecAtomWriterSpy);
+ }
+
+ @Test
+ public void testEarcStatusChanged_handleEarcStateChange_writesAtom() {
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
+ mTestLooper.dispatchAll();
+ Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
+
+ mHdmiControlServiceSpy.handleEarcStateChange(HDMI_EARC_STATUS_EARC_PENDING,
+ EARC_PORT_ID);
+ verify(mHdmiCecAtomWriterSpy, times(1))
+ .earcStatusChanged(true, true, HDMI_EARC_STATUS_EARC_PENDING,
+ HDMI_EARC_STATUS_EARC_PENDING,
+ HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED);
+ }
+
+ @Test
+ public void testEarcStatusChanged_onWakeUp_earcSupported_earcEnabled_writesAtom() {
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
+ Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
+ verify(mHdmiCecAtomWriterSpy, times(1))
+ .earcStatusChanged(true, true, HDMI_EARC_STATUS_EARC_PENDING,
+ HDMI_EARC_STATUS_EARC_PENDING, HdmiStatsEnums.LOG_REASON_WAKE);
+ }
+
+ @Test
+ public void testEarcStatusChanged_onWakeUp_earcSupported_earcDisabled_writesAtom() {
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
+ Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
+ verify(mHdmiCecAtomWriterSpy, times(1))
+ .earcStatusChanged(true, false, HDMI_EARC_STATUS_UNKNOWN,
+ HDMI_EARC_STATUS_UNKNOWN, HdmiStatsEnums.LOG_REASON_WAKE);
+ }
+
+ @Test
+ public void testEarcStatusChanged_onWakeUp_earcNotSupported_earcEnabled_writesAtom() {
+ doReturn(false).when(mHdmiControlServiceSpy).isEarcSupported();
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
+ Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
+ verify(mHdmiCecAtomWriterSpy, times(1))
+ .earcStatusChanged(false, true, HDMI_EARC_STATUS_UNKNOWN,
+ HDMI_EARC_STATUS_UNKNOWN, HdmiStatsEnums.LOG_REASON_WAKE);
+ }
+
+ @Test
+ public void testEarcStatusChanged_onWakeUp_earcNotSupported_earcDisabled_writesAtom() {
+ doReturn(false).when(mHdmiControlServiceSpy).isEarcSupported();
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
+ Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
+ verify(mHdmiCecAtomWriterSpy, times(1))
+ .earcStatusChanged(false, false, HDMI_EARC_STATUS_UNKNOWN,
+ HDMI_EARC_STATUS_UNKNOWN, HdmiStatsEnums.LOG_REASON_WAKE);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 9882670..3dd8312 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -504,6 +504,19 @@
}
@Test
+ public void handleUserControlPressed_ignoreAdditionalParameters() {
+ byte[] params = new byte[] {
+ (byte) (HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION & 0xFF), (byte) 0xFF};
+ mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
+ @Constants.HandleMessageResult int result = mHdmiLocalDevice.handleUserControlPressed(
+ HdmiCecMessageBuilder.buildUserControlPressed(ADDR_TV, ADDR_PLAYBACK_1, params));
+
+ assertEquals(Constants.HANDLED, result);
+ assertThat(mWakeupMessageReceived).isTrue();
+ assertThat(mStandbyMessageReceived).isFalse();
+ }
+
+ @Test
public void handleVendorCommand_notHandled() {
HdmiCecMessage vendorCommand = HdmiCecMessageBuilder.buildVendorCommand(ADDR_TV,
ADDR_PLAYBACK_1, new byte[]{0});
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index d52b7ea..55e5dbd 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -1013,6 +1013,24 @@
}
@Test
+ public void receiveSetAudioVolumeLevel_volumeOutOfBounds_noVolumeChange() {
+ mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25);
+
+ // Max volume of STREAM_MUSIC is retrieved on boot
+ mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.onCecMessage(SetAudioVolumeLevelMessage.build(
+ ADDR_PLAYBACK_1,
+ ADDR_TV,
+ 127));
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(),
+ anyInt());
+ }
+
+ @Test
public void tvSendRequestArcTerminationOnSleep() {
// Emulate Audio device on port 0x2000 (supports ARC)
mNativeWrapper.setPortConnectionStatus(2, true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
index 1bc99b6..f608c235 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -169,6 +169,11 @@
}
@Override
+ boolean isPowerStandby() {
+ return false;
+ }
+
+ @Override
protected HdmiCecConfig getHdmiCecConfig() {
return hdmiCecConfig;
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionPlaybackTest.java
new file mode 100644
index 0000000..9022b18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionPlaybackTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hdmi;
+
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import static com.android.server.hdmi.SendCecCommandAction.SEND_COMMAND_RETRY_MS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Looper;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collections;
+
+/** Tests for {@link SendCecCommandAction} */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class SendCecCommandActionPlaybackTest {
+ private static final String TAG = "SendCecCommandActionPlaybackTest";
+ private HdmiControlService mHdmiControlService;
+ private HdmiCecLocalDevice mPlaybackDevice;
+ private FakeNativeWrapper mNativeWrapper;
+ private FakePowerManagerWrapper mPowerManager;
+ private Looper mMyLooper;
+ private TestLooper mTestLooper = new TestLooper();
+ private int mPhysicalAddress;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ FakeAudioFramework audioFramework = new FakeAudioFramework();
+
+ mHdmiControlService = new HdmiControlService(context,
+ Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK),
+ audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) {
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
+
+ @Override
+ protected void writeStringSystemProperty(String key, String value) {
+ // do nothing
+ }
+ };
+
+ mMyLooper = mTestLooper.getLooper();
+ mHdmiControlService.setIoLooper(mMyLooper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
+ mNativeWrapper = new FakeNativeWrapper();
+ HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+ this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ mHdmiControlService.setCecController(hdmiCecController);
+ mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+ mHdmiControlService.initService();
+ mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
+ mPowerManager = new FakePowerManagerWrapper(context);
+ mHdmiControlService.setPowerManager(mPowerManager);
+ mPhysicalAddress = 0x2000;
+ mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
+ mTestLooper.dispatchAll();
+ mPlaybackDevice = mHdmiControlService.playback();
+
+ mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
+ }
+
+ @Test
+ public void sendCecCommand_activeSource_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_ACTIVE_SOURCE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(activeSource);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ }
+
+ @Test
+ public void sendCecCommand_inactiveSource_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_INACTIVE_SOURCE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage inactiveSourceMessage = HdmiCecMessageBuilder.buildInactiveSource(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(inactiveSourceMessage);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSourceMessage);
+ }
+
+ @Test
+ public void sendCecCommand_routingChange_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_ROUTING_CHANGE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ int otherPhysicalAddress = 0x3000;
+ HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress,
+ otherPhysicalAddress);
+ mHdmiControlService.sendCecCommand(routingChange);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(routingChange);
+ }
+
+ @Test
+ public void sendCecCommand_setStreamPath_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_SET_STREAM_PATH,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ int otherPhysicalAddress = 0x3000;
+ HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), otherPhysicalAddress);
+ mHdmiControlService.sendCecCommand(setStreamPath);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(setStreamPath);
+ }
+
+ @Test
+ public void sendCecCommand_textViewOn_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_TEXT_VIEW_ON, SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(textViewOn);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
+ public void sendCecCommand_imageViewOn_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_IMAGE_VIEW_ON,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage imageViewOn = HdmiCecMessageBuilder.buildImageViewOn(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(imageViewOn);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(imageViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(imageViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(imageViewOn);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(imageViewOn);
+ }
+
+ @Test
+ public void sendCecCommand_activeSource_sendMessageSuccess_noResendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_ACTIVE_SOURCE,
+ SendMessageResult.SUCCESS);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(activeSource);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ }
+
+ @Test
+ public void sendCecCommand_reportPhysicalAddress_sendMessageFails_noResendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
+ .buildReportPhysicalAddressCommand(
+ mPlaybackDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress,
+ Constants.ALL_DEVICE_TYPES_PLAYBACK);
+ mHdmiControlService.sendCecCommand(reportPhysicalAddress);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportPhysicalAddress);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPhysicalAddress);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionTvTest.java
new file mode 100644
index 0000000..aae8398
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SendCecCommandActionTvTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hdmi;
+
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import static com.android.server.hdmi.SendCecCommandAction.SEND_COMMAND_RETRY_MS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Looper;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collections;
+
+/** Tests for {@link SendCecCommandAction} */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class SendCecCommandActionTvTest {
+ private static final String TAG = "SendCecCommandActionTvTest";
+ private HdmiControlService mHdmiControlService;
+ private HdmiCecLocalDevice mTvDevice;
+ private FakeNativeWrapper mNativeWrapper;
+ private FakePowerManagerWrapper mPowerManager;
+ private Looper mMyLooper;
+ private TestLooper mTestLooper = new TestLooper();
+ private int mPhysicalAddress;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ FakeAudioFramework audioFramework = new FakeAudioFramework();
+
+ mHdmiControlService = new HdmiControlService(context,
+ Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
+ audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) {
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
+
+ @Override
+ protected void writeStringSystemProperty(String key, String value) {
+ // do nothing
+ }
+
+ @Override
+ boolean verifyPhysicalAddresses(HdmiCecMessage message) {
+ return true;
+ }
+ };
+
+ mMyLooper = mTestLooper.getLooper();
+ mHdmiControlService.setIoLooper(mMyLooper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
+ mNativeWrapper = new FakeNativeWrapper();
+ HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+ this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ mHdmiControlService.setCecController(hdmiCecController);
+ mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+ mHdmiControlService.initService();
+ mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
+ mPowerManager = new FakePowerManagerWrapper(context);
+ mHdmiControlService.setPowerManager(mPowerManager);
+ mPhysicalAddress = 0x0000;
+ mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
+ mTestLooper.dispatchAll();
+ mTvDevice = mHdmiControlService.tv();
+
+ mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
+ }
+
+ @Test
+ public void sendCecCommand_activeSource_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_ACTIVE_SOURCE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(activeSource);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ }
+
+ @Test
+ public void sendCecCommand_inactiveSource_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_INACTIVE_SOURCE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage inactiveSourceMessage = HdmiCecMessageBuilder.buildInactiveSource(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress);
+ mHdmiControlService.sendCecCommand(inactiveSourceMessage);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSourceMessage);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSourceMessage);
+ }
+
+ @Test
+ public void sendCecCommand_routingChange_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_ROUTING_CHANGE,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ int otherPhysicalAddress = 0x3000;
+ HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), mPhysicalAddress,
+ otherPhysicalAddress);
+ mHdmiControlService.sendCecCommand(routingChange);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(routingChange);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(routingChange);
+ }
+
+ @Test
+ public void sendCecCommand_setStreamPath_sendMessageFails_resendMessage() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_SET_STREAM_PATH,
+ SendMessageResult.BUSY);
+ mTestLooper.dispatchAll();
+ int otherPhysicalAddress = 0x3000;
+ HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+ mTvDevice.getDeviceInfo().getLogicalAddress(), otherPhysicalAddress);
+ mHdmiControlService.sendCecCommand(setStreamPath);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(SEND_COMMAND_RETRY_MS);
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(setStreamPath);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index c546a74..c09e09c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
import android.app.KeyguardManager;
import android.content.Context;
@@ -54,6 +55,7 @@
import java.io.File;
import java.security.KeyStore;
+import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import java.util.List;
@@ -393,6 +395,18 @@
}
@Test
+ public void getEncryptKey_noScreenlock() throws Exception {
+ when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(false);
+ doThrow(new KeyStoreException()).when(mKeyStoreProxy).setEntry(
+ anyString(),
+ any(),
+ any());
+
+ assertThrows(InsecureUserException.class,
+ () -> mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE));
+ }
+
+ @Test
public void getDecryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
eq(DECRYPTION_KEY_ALIAS_1),
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index b91a6cb..c42928e 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -344,7 +344,7 @@
// Second start - so not valid.
projection.start(mIMediaProjectionCallback);
- assertThrows(IllegalStateException.class, projection::isValid);
+ assertThrows(SecurityException.class, projection::isValid);
}
// TODO(269273190): Test flag using compat annotations instead.
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 52c6777..24029b1 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -16,15 +16,18 @@
package com.android.server.os;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.app.role.RoleManager;
import android.content.Context;
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
import android.os.IBinder;
import android.os.IDumpstateListener;
+import android.os.Process;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Pair;
@@ -37,21 +40,23 @@
import org.junit.runner.RunWith;
import java.io.FileDescriptor;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class BugreportManagerServiceImplTest {
- Context mContext;
- BugreportManagerServiceImpl mService;
- BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
+ private Context mContext;
+ private BugreportManagerServiceImpl mService;
+ private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
- int mCallingUid = 1234;
- String mCallingPackage = "test.package";
+ private int mCallingUid = 1234;
+ private String mCallingPackage = "test.package";
- String mBugreportFile = "bugreport-file.zip";
- String mBugreportFile2 = "bugreport-file2.zip";
+ private String mBugreportFile = "bugreport-file.zip";
+ private String mBugreportFile2 = "bugreport-file2.zip";
@Before
public void setUp() {
@@ -109,6 +114,36 @@
BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
}
+ @Test
+ public void testCancelBugreportWithoutRole() throws Exception {
+ // Clear out allowlisted packages.
+ mService = new BugreportManagerServiceImpl(
+ new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
+
+ assertThrows(SecurityException.class, () -> mService.cancelBugreport(
+ Binder.getCallingUid(), mContext.getPackageName()));
+ }
+
+ @Test
+ public void testCancelBugreportWithRole() throws Exception {
+ // Clear out allowlisted packages.
+ mService = new BugreportManagerServiceImpl(
+ new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
+ RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+ CallbackFuture future = new CallbackFuture();
+ runWithShellPermissionIdentity(() -> roleManager.setBypassingRoleQualification(true));
+ runWithShellPermissionIdentity(() -> roleManager.addRoleHolderAsUser(
+ "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+ mContext.getPackageName(),
+ /* flags= */ 0,
+ Process.myUserHandle(),
+ mContext.getMainExecutor(),
+ future));
+
+ assertThat(future.get()).isEqualTo(true);
+ mService.cancelBugreport(Binder.getCallingUid(), mContext.getPackageName());
+ }
+
private static class Listener implements IDumpstateListener {
CountDownLatch mLatch;
int mErrorCode;
@@ -149,4 +184,12 @@
return mErrorCode;
}
}
+
+ private static class CallbackFuture extends CompletableFuture<Boolean>
+ implements Consumer<Boolean> {
+ @Override
+ public void accept(Boolean successful) {
+ complete(successful);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 9718604..7d0f361 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -53,6 +53,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -592,23 +594,42 @@
public void testRemoveUserWhenPossible_withProfiles() throws Exception {
assumeHeadlessModeEnabled();
assumeCloneEnabled();
- final UserInfo parentUser = createUser("Human User", /* flags= */ 0);
- final UserInfo cloneProfileUser = createProfileForUser("Clone Profile user",
+ final List<String> profileTypesToCreate = Arrays.asList(
UserManager.USER_TYPE_PROFILE_CLONE,
- parentUser.id);
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ );
- final UserInfo workProfileUser = createProfileForUser("Work Profile user",
- UserManager.USER_TYPE_PROFILE_MANAGED,
- parentUser.id);
+ final UserInfo parentUser = createUser("Human User", /* flags= */ 0);
+ assertWithMessage("Could not create parent user")
+ .that(parentUser).isNotNull();
+
+ final List<Integer> profileIds = new ArrayList<>();
+ for (String profileType : profileTypesToCreate) {
+ final String name = profileType.substring(profileType.lastIndexOf('.') + 1);
+ if (mUserManager.canAddMoreProfilesToUser(profileType, parentUser.id)) {
+ final UserInfo profile = createProfileForUser(name, profileType, parentUser.id);
+ assertWithMessage("Could not create " + name)
+ .that(profile).isNotNull();
+ profileIds.add(profile.id);
+ } else {
+ Slog.w(TAG, "Can not add " + name + " to user #" + parentUser.id);
+ }
+ }
+
+ // Test shouldn't pass or fail unless it's allowed to add profiles to secondary users.
+ assumeTrue("Not possible to create any profiles to user #" + parentUser.id,
+ profileIds.size() > 0);
assertThat(mUserManager.removeUserWhenPossible(parentUser.getUserHandle(),
/* overrideDevicePolicy= */ false))
.isEqualTo(UserManager.REMOVE_RESULT_REMOVED);
waitForUserRemoval(parentUser.id);
- assertThat(hasUser(parentUser.id)).isFalse();
- assertThat(hasUser(cloneProfileUser.id)).isFalse();
- assertThat(hasUser(workProfileUser.id)).isFalse();
+ assertWithMessage("Parent user still exists")
+ .that(hasUser(parentUser.id)).isFalse();
+ profileIds.forEach(id ->
+ assertWithMessage("Profile still exists")
+ .that(hasUser(id)).isFalse());
}
/** Tests creating a FULL user via specifying userType. */
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index 0b13f9a..5bd7116 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -47,11 +47,7 @@
private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
private static final float PRECISION = 0.001f;
private static final int GPS_MODE = 0; // LOCATION_MODE_NO_CHANGE
- private static final int DEFAULT_GPS_MODE =
- PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
private static final int SOUND_TRIGGER_MODE = 0; // SOUND_TRIGGER_MODE_ALL_ENABLED
- private static final int DEFAULT_SOUND_TRIGGER_MODE =
- PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
private static final String BATTERY_SAVER_CONSTANTS = "disable_vibration=false,"
+ "advertise_is_enabled=true,"
+ "disable_animation=false,"
@@ -117,7 +113,9 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
- testServiceDefaultValue_Off(ServiceType.VIBRATION);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_disableVibration,
+ ServiceType.VIBRATION);
}
@SmallTest
@@ -128,27 +126,39 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.SOUND);
+ final int defaultMode = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_batterySaver_full_soundTriggerMode);
+ if (defaultMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED) {
+ testServiceDefaultValue_Off(ServiceType.SOUND);
+ } else {
+ testServiceDefaultValue_On(ServiceType.SOUND);
+ }
mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
PowerSaveState stateOn =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND);
- assertThat(stateOn.soundTriggerMode).isEqualTo(DEFAULT_SOUND_TRIGGER_MODE);
+ assertThat(stateOn.soundTriggerMode).isEqualTo(defaultMode);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.FULL_BACKUP);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_deferFullBackup,
+ ServiceType.FULL_BACKUP);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.KEYVALUE_BACKUP);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_deferKeyValueBackup,
+ ServiceType.KEYVALUE_BACKUP);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
- testServiceDefaultValue_Off(ServiceType.ANIMATION);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_disableAnimation,
+ ServiceType.ANIMATION);
}
@SmallTest
@@ -158,46 +168,53 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.NETWORK_FIREWALL);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_enableFirewall,
+ ServiceType.NETWORK_FIREWALL);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyNightMode_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.NIGHT_MODE);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_enableNightMode,
+ ServiceType.NIGHT_MODE);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyDataSaver_DefaultValueCorrect() {
- mBatterySaverPolicy.updateConstantsLocked("", "");
- mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
- final PowerSaveState batterySaverStateOn =
- mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.DATA_SAVER);
- assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
-
- mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_OFF);
- final PowerSaveState batterySaverStateOff = mBatterySaverPolicy.getBatterySaverPolicy(
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_enableDataSaver,
ServiceType.DATA_SAVER);
- assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
- testServiceDefaultValue_Off(ServiceType.SCREEN_BRIGHTNESS);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_enableAdjustBrightness,
+ ServiceType.SCREEN_BRIGHTNESS);
}
@SmallTest
- public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.LOCATION);
+ public void testGetBatterySaverPolicy_PolicyLocation_DefaultValueCorrect() {
+ final int defaultMode = getContext().getResources()
+ .getInteger(com.android.internal.R.integer.config_batterySaver_full_locationMode);
+ if (defaultMode == PowerManager.LOCATION_MODE_NO_CHANGE) {
+ testServiceDefaultValue_Off(ServiceType.LOCATION);
+ } else {
+ testServiceDefaultValue_On(ServiceType.LOCATION);
+ }
mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
PowerSaveState stateOn =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION);
- assertThat(stateOn.locationMode).isEqualTo(DEFAULT_GPS_MODE);
+ assertThat(stateOn.locationMode).isEqualTo(defaultMode);
}
@SmallTest
public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.QUICK_DOZE);
+ testDefaultValue(
+ com.android.internal.R.bool.config_batterySaver_full_enableQuickDoze,
+ ServiceType.QUICK_DOZE);
}
@SmallTest
@@ -264,6 +281,14 @@
mBatterySaverPolicy.updateConstantsLocked(null, "");
}
+ private void testDefaultValue(int boolResId, @ServiceType int type) {
+ if (getContext().getResources().getBoolean(boolResId)) {
+ testServiceDefaultValue_On(type);
+ } else {
+ testServiceDefaultValue_Off(type);
+ }
+ }
+
private void testServiceDefaultValue_On(@ServiceType int type) {
mBatterySaverPolicy.updateConstantsLocked("", "");
mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index e65229f..1ba1462 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -93,8 +93,6 @@
@Test
public void testAtraceBinaryState1() {
- mHistory.forceRecordAllHistory();
-
InOrder inOrder = Mockito.inOrder(mTracer);
Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
@@ -112,8 +110,6 @@
@Test
public void testAtraceBinaryState2() {
- mHistory.forceRecordAllHistory();
-
InOrder inOrder = Mockito.inOrder(mTracer);
Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
@@ -131,8 +127,6 @@
@Test
public void testAtraceNumericalState() {
- mHistory.forceRecordAllHistory();
-
InOrder inOrder = Mockito.inOrder(mTracer);
Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
@@ -150,8 +144,6 @@
@Test
public void testAtraceInstantEvent() {
- mHistory.forceRecordAllHistory();
-
InOrder inOrder = Mockito.inOrder(mTracer);
Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index 6a1674b..fc4e6e0 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -41,9 +41,11 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.util.FakeLatencyTracker;
+import com.android.modules.utils.testing.TestableDeviceConfig.TestableDeviceConfigRule;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -54,6 +56,9 @@
@RunWith(JUnit4.class)
public class SoundTriggerMiddlewareLoggingLatencyTest {
+ @Rule
+ public TestableDeviceConfigRule mDeviceConfigRule = new TestableDeviceConfigRule();
+
private FakeLatencyTracker mLatencyTracker;
@Mock
private BatteryStatsInternal mBatteryStatsInternal;
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 37e5da5..9c79375 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -96,6 +96,19 @@
android:theme="@style/WhiteBackgroundTheme"
android:exported="true"/>
+ <activity android:name="com.android.server.wm.TrustedPresentationCallbackTest$TestActivity"
+ android:exported="true"
+ android:showWhenLocked="true"
+ android:turnScreenOn="true" />
+
+ <activity
+ android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:enabled="true">
diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
index 6a9f283..c3b7849 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
@@ -21,6 +21,7 @@
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS;
import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_POWER_DREAM_OR_SLEEP;
+import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_POWER_GO_TO_SLEEP;
import android.provider.Settings;
import android.view.Display;
@@ -39,6 +40,7 @@
*/
@Test
public void testPowerSinglePress() {
+ mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_GO_TO_SLEEP);
sendKey(KEYCODE_POWER);
mPhoneWindowManager.assertPowerSleep();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
index 07d8b8a..5125594 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
@@ -17,17 +17,16 @@
package com.android.server.wm;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceStateManager;
import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -38,6 +37,8 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.List;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@@ -58,6 +59,7 @@
private DeviceStateController.DeviceState mCurrentState =
DeviceStateController.DeviceState.UNKNOWN;
private Consumer<DeviceStateController.DeviceState> mDelegate;
+ private Executor mExecutor = MoreExecutors.directExecutor();
@Before
public void setUp() {
@@ -124,13 +126,31 @@
mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
- // The callback should not receive state change when the it is unregistered.
+ // The callback should not receive state change when it is unregistered.
mTarget.unregisterDeviceStateCallback(mDelegate);
assertTrue(mTarget.mDeviceStateCallbacks.isEmpty());
mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */, mCurrentState);
}
+ @Test
+ public void testCopyDeviceStateCallbacks() {
+ initialize(true /* supportFold */, true /* supportHalfFolded */);
+ assertEquals(1, mTarget.mDeviceStateCallbacks.size());
+ assertTrue(mTarget.mDeviceStateCallbacks.containsKey(mDelegate));
+
+ List<Pair<Consumer<DeviceStateController.DeviceState>, Executor>> entries =
+ mTarget.copyDeviceStateCallbacks();
+ mTarget.unregisterDeviceStateCallback(mDelegate);
+
+ // In contrast to List<Map.Entry> where the entries are tied to changes in the backing map,
+ // List<Pair> should still contain non-null callbacks and executors even though they were
+ // removed from the backing map via the unregister method above.
+ assertEquals(1, entries.size());
+ assertEquals(mDelegate, entries.get(0).first);
+ assertEquals(mExecutor, entries.get(0).second);
+ }
+
private final int[] mFoldedStates = {0};
private final int[] mOpenDeviceStates = {1};
private final int[] mHalfFoldedStates = {2};
@@ -194,7 +214,7 @@
when(mMockContext.getResources()).thenReturn((mockRes));
mockFold(mSupportFold, mSupportHalfFold);
mTarget = new DeviceStateController(mMockContext, new WindowManagerGlobalLock());
- mTarget.registerDeviceStateCallback(mDelegate, MoreExecutors.directExecutor());
+ mTarget.registerDeviceStateCallback(mDelegate, mExecutor);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 8e015d4..769a309 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -103,8 +103,7 @@
public void setUp() throws Exception {
mLetterboxConfiguration = mDisplayContent.mWmService.mLetterboxConfiguration;
spyOn(mLetterboxConfiguration);
- when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ anyBoolean()))
+ when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
.thenReturn(true);
when(mLetterboxConfiguration.isCameraCompatRefreshEnabled())
.thenReturn(true);
@@ -177,8 +176,7 @@
@Test
public void testOnScreenRotationAnimationFinished_treatmentNotEnabled_doNotShowToast() {
- when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ anyBoolean()))
+ when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
.thenReturn(false);
spyOn(mDisplayRotationCompatPolicy);
@@ -238,8 +236,7 @@
@Test
public void testTreatmentNotEnabled_noForceRotationOrRefresh() throws Exception {
- when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ anyBoolean()))
+ when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
.thenReturn(false);
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -253,8 +250,7 @@
@Test
public void testTreatmentDisabledViaDeviceConfig_noForceRotationOrRefresh() throws Exception {
- when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
- /* checkDeviceConfig */ true))
+ when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled())
.thenReturn(false);
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
index d29b18f..b105703 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
@@ -31,7 +31,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
@@ -79,8 +78,11 @@
when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(true);
mMockLetterboxConfiguration = mock(LetterboxConfiguration.class);
- when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled(
- /* checkDeviceConfig */ anyBoolean())).thenReturn(true);
+ when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled())
+ .thenReturn(true);
+ when(mMockLetterboxConfiguration
+ .isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime())
+ .thenReturn(true);
mPolicy = DisplayRotationImmersiveAppCompatPolicy.createIfNeeded(
mMockLetterboxConfiguration, createDisplayRotationMock(),
@@ -204,8 +206,8 @@
@Test
public void testRotationChoiceEnforcedOnly_featureFlagDisabled_lockNotEnforced() {
- when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled(
- /* checkDeviceConfig */ true)).thenReturn(false);
+ when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled())
+ .thenReturn(false);
assertIsRotationLockEnforcedReturnsFalseForAllRotations();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationDeviceConfigTests.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationDeviceConfigTests.java
deleted file mode 100644
index 2b7a06b..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationDeviceConfigTests.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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 com.android.server.wm.LetterboxConfigurationDeviceConfig.sKeyToDefaultValueMap;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-import android.provider.DeviceConfig;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.modules.utils.testing.TestableDeviceConfig;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import java.util.Map;
-
-/**
- * Test class for {@link LetterboxConfigurationDeviceConfig}.
- *
- * atest WmTests:LetterboxConfigurationDeviceConfigTests
- */
-@SmallTest
-@Presubmit
-public class LetterboxConfigurationDeviceConfigTests {
-
- private LetterboxConfigurationDeviceConfig mDeviceConfig;
-
- @Rule
- public final TestableDeviceConfig.TestableDeviceConfigRule
- mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
-
- @Before
- public void setUp() {
- mDeviceConfig = new LetterboxConfigurationDeviceConfig(/* executor */ Runnable::run);
- }
-
- @Test
- public void testGetFlag_flagIsActive_flagChanges() throws Throwable {
- for (Map.Entry<String, Boolean> entry : sKeyToDefaultValueMap.entrySet()) {
- testGetFlagForKey_flagIsActive_flagChanges(entry.getKey(), entry.getValue());
- }
- }
-
- private void testGetFlagForKey_flagIsActive_flagChanges(final String key, boolean defaultValue)
- throws InterruptedException {
- mDeviceConfig.updateFlagActiveStatus(/* isActive */ true, key);
-
- assertEquals("Unexpected default value for " + key,
- mDeviceConfig.getFlag(key), defaultValue);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, key,
- /* value */ Boolean.TRUE.toString(), /* makeDefault */ false);
-
- assertTrue("Flag " + key + "is not true after change", mDeviceConfig.getFlag(key));
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, key,
- /* value */ Boolean.FALSE.toString(), /* makeDefault */ false);
-
- assertFalse("Flag " + key + "is not false after change", mDeviceConfig.getFlag(key));
- }
-
- @Test
- public void testGetFlag_flagIsNotActive_alwaysReturnDefaultValue() throws Throwable {
- for (Map.Entry<String, Boolean> entry : sKeyToDefaultValueMap.entrySet()) {
- testGetFlagForKey_flagIsNotActive_alwaysReturnDefaultValue(
- entry.getKey(), entry.getValue());
- }
- }
-
- private void testGetFlagForKey_flagIsNotActive_alwaysReturnDefaultValue(final String key,
- boolean defaultValue) throws InterruptedException {
- assertEquals("Unexpected default value for " + key,
- mDeviceConfig.getFlag(key), defaultValue);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, key,
- /* value */ Boolean.TRUE.toString(), /* makeDefault */ false);
-
- assertEquals("Flag " + key + "is not set to default after change",
- mDeviceConfig.getFlag(key), defaultValue);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, key,
- /* value */ Boolean.FALSE.toString(), /* makeDefault */ false);
-
- assertEquals("Flag " + key + "is not set to default after change",
- mDeviceConfig.getFlag(key), defaultValue);
- }
-
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 34a13bf..81a3794 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -63,7 +63,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
@@ -147,7 +146,9 @@
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
public void testShouldIgnoreRequestedOrientation_cameraCompatTreatment_returnsTrue() {
- doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled(anyBoolean());
+ doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled();
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabledAtBuildTime();
// Recreate DisplayContent with DisplayRotationCompatPolicy
mActivity = setUpActivityWithComponent();
@@ -306,7 +307,7 @@
@Test
public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertFalse(mController.shouldRefreshActivityForCameraCompat());
}
@@ -315,7 +316,7 @@
@EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertFalse(mController.shouldRefreshActivityForCameraCompat());
}
@@ -325,7 +326,7 @@
public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
@@ -337,7 +338,7 @@
public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ false);
mController = new LetterboxUiController(mWm, mActivity);
@@ -349,7 +350,7 @@
public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
@@ -363,7 +364,7 @@
@EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
}
@@ -372,7 +373,7 @@
@EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
}
@@ -382,7 +383,7 @@
public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsFalseAndOverride_returnFalse()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ false);
mController = new LetterboxUiController(mWm, mActivity);
@@ -394,7 +395,7 @@
public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
@@ -407,7 +408,7 @@
@Test
public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertFalse(mController.shouldForceRotateForCameraCompat());
}
@@ -416,7 +417,7 @@
@EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
assertFalse(mController.shouldForceRotateForCameraCompat());
}
@@ -426,7 +427,7 @@
public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
@@ -438,7 +439,7 @@
public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ false);
mController = new LetterboxUiController(mWm, mActivity);
@@ -450,7 +451,7 @@
public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue()
throws Exception {
doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ .isCameraCompatTreatmentEnabled();
mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
@@ -741,7 +742,9 @@
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT,
OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
public void testOverrideOrientationIfNeeded_whenCameraNotActive_returnsUnchanged() {
- doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled(anyBoolean());
+ doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled();
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabledAtBuildTime();
// Recreate DisplayContent with DisplayRotationCompatPolicy
mActivity = setUpActivityWithComponent();
@@ -759,7 +762,9 @@
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT,
OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
public void testOverrideOrientationIfNeeded_whenCameraActive_returnsPortrait() {
- doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled(anyBoolean());
+ doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled();
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabledAtBuildTime();
// Recreate DisplayContent with DisplayRotationCompatPolicy
mActivity = setUpActivityWithComponent();
@@ -1060,7 +1065,9 @@
@Test
public void testgetFixedOrientationLetterboxAspectRatio_splitScreenAspectEnabled() {
doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled(anyBoolean());
+ .isCameraCompatTreatmentEnabled();
+ doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabledAtBuildTime();
doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)
.isCameraCompatSplitScreenAspectRatioEnabled();
doReturn(false).when(mActivity.mWmService.mLetterboxConfiguration)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
index 1ee0959..b181213 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
@@ -43,16 +43,14 @@
import android.os.Looper;
import android.os.ServiceManager;
import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
import android.view.IWindowManager;
import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.cts.surfacevalidator.BitmapPixelChecker;
import android.view.cts.surfacevalidator.SaveBitmapHelper;
import android.window.ScreenCapture;
-import android.window.ScreenCapture.ScreenCaptureListener;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
-import android.window.ScreenCapture.ScreenshotSync;
+import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
@@ -169,10 +167,10 @@
.setPosition(sc, point.x, point.y)
.apply(true);
- Pair<ScreenCaptureListener, ScreenshotSync> syncScreenCapture =
+ SynchronousScreenCaptureListener syncScreenCapture =
ScreenCapture.createSyncCaptureListener();
- windowManager.captureDisplay(DEFAULT_DISPLAY, null, syncScreenCapture.first);
- ScreenshotHardwareBuffer hardwareBuffer = syncScreenCapture.second.get();
+ windowManager.captureDisplay(DEFAULT_DISPLAY, null, syncScreenCapture);
+ ScreenshotHardwareBuffer hardwareBuffer = syncScreenCapture.getBuffer();
assertNotNull(hardwareBuffer);
Bitmap screenshot = hardwareBuffer.asBitmap();
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 27e6e31..3908947 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -2047,6 +2047,72 @@
}
@Test
+ public void testDefaultLetterboxAspectRatioForMultiWindowMode_fixedOrientationApp() {
+ // Set-up display in portrait.
+ mAtm.mDevEnableNonResizableMultiWindow = true;
+ final int screenWidth = 1100;
+ final int screenHeight = 2100;
+ setUpDisplaySizeWithApp(screenWidth, screenHeight);
+
+ mActivity.mDisplayContent.getWindowConfiguration()
+ .setAppBounds(/* left */ 0, /* top */ 0, screenWidth, screenHeight);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to multi-window which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, screenWidth, getExpectedSplitSize(screenHeight));
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // Unresizable portrait-only activity.
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Activity should be letterboxed with an aspect ratio of 1.01.
+ final Rect afterBounds = mActivity.getBounds();
+ final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
+ assertEquals(LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW,
+ actualAspectRatio, 0.001f);
+ assertTrue(mActivity.areBoundsLetterboxed());
+ }
+
+ @Test
+ public void
+ testDefaultLetterboxAspectRatioForMultiWindowMode_fixedOrientationAppWithMinRatio() {
+ // Set-up display in portrait.
+ mAtm.mDevEnableNonResizableMultiWindow = true;
+ final int screenWidth = 1100;
+ final int screenHeight = 2100;
+ setUpDisplaySizeWithApp(screenWidth, screenHeight);
+
+ mActivity.mDisplayContent.getWindowConfiguration()
+ .setAppBounds(/* left */ 0, /* top */ 0, screenWidth, screenHeight);
+
+ // Set min aspect ratio to value greater than the default letterbox aspect ratio for
+ // multi-window mode.
+ final float minAspectRatio = 1.2f;
+ mActivity.info.setMinAspectRatio(minAspectRatio);
+
+ final TestSplitOrganizer organizer =
+ new TestSplitOrganizer(mAtm, mActivity.getDisplayContent());
+ // Move activity to multi-window which takes half of the screen.
+ mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+ organizer.mPrimary.setBounds(0, 0, screenWidth, getExpectedSplitSize(screenHeight));
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+ assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode());
+
+ // Unresizable portrait-only activity.
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ // Activity should be letterboxed with the min aspect ratio requested by the app NOT the
+ // default letterbox aspect ratio for multi-window.
+ final Rect afterBounds = mActivity.getBounds();
+ final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
+ assertEquals(minAspectRatio, actualAspectRatio, 0.001f);
+ assertTrue(mActivity.areBoundsLetterboxed());
+ }
+
+ @Test
public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SynchedDeviceConfigTests.java b/services/tests/wmtests/src/com/android/server/wm/SynchedDeviceConfigTests.java
new file mode 100644
index 0000000..7d44e11
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/SynchedDeviceConfigTests.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+
+import android.app.ActivityThread;
+import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.modules.utils.testing.TestableDeviceConfig;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class for {@link SynchedDeviceConfig}.
+ *
+ * atest WmTests:SynchedDeviceConfigTests
+ */
+@SmallTest
+@Presubmit
+public class SynchedDeviceConfigTests {
+
+ private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
+ private static final String NAMESPACE_FOR_TEST = "TestingNameSpace";
+
+ private SynchedDeviceConfig mDeviceConfig;
+
+ private Executor mExecutor;
+
+ @Rule
+ public final TestableDeviceConfig.TestableDeviceConfigRule
+ mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+ @Before
+ public void setUp() {
+ mExecutor = Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor();
+ mDeviceConfig = SynchedDeviceConfig
+ .builder(/* nameSpace */ NAMESPACE_FOR_TEST, /* executor */ mExecutor)
+ .addDeviceConfigEntry(/* key */ "key1", /* default */ true, /* enabled */ true)
+ .addDeviceConfigEntry(/* key */ "key2", /* default */ false, /* enabled */ true)
+ .addDeviceConfigEntry(/* key */ "key3", /* default */ true, /* enabled */ false)
+ .addDeviceConfigEntry(/* key */ "key4", /* default */ false, /* enabled */ false)
+ .build();
+ }
+
+ @After
+ public void tearDown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfig);
+ }
+
+ @Test
+ public void testWhenStarted_initialValuesAreDefaultOrFalseIfDisabled() {
+ assertFlagValue(/* key */ "key1", /* expected */ true); // enabled
+ assertFlagValue(/* key */ "key2", /* expected */ false); // enabled
+ assertFlagValue(/* key */ "key3", /* expected */ false); // disabled
+ assertFlagValue(/* key */ "key4", /* expected */ false); // disabled
+ }
+
+ @Test
+ public void testIsEnabled() {
+ assertFlagEnabled(/* key */ "key1", /* expected */ true);
+ assertFlagEnabled(/* key */ "key2", /* expected */ true);
+ assertFlagEnabled(/* key */ "key3", /* expected */ false);
+ assertFlagEnabled(/* key */ "key4", /* expected */ false);
+ }
+
+ @Test
+ public void testWhenUpdated_onlyEnabledChanges() {
+ final CountDownLatch countDownLatch = new CountDownLatch(4);
+ spyOn(mDeviceConfig);
+ doAnswer(invocation -> {
+ invocation.callRealMethod();
+ countDownLatch.countDown();
+ return null;
+ }).when(mDeviceConfig).onPropertiesChanged(any());
+ try {
+ // We update all the keys
+ updateProperty(/* key */ "key1", /* value */ false);
+ updateProperty(/* key */ "key2", /* value */ true);
+ updateProperty(/* key */ "key3", /* value */ false);
+ updateProperty(/* key */ "key4", /* value */ true);
+
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+
+ // We update all the flags but only the enabled ones change
+ assertFlagValue(/* key */ "key1", /* expected */ false); // changes
+ assertFlagValue(/* key */ "key2", /* expected */ true); // changes
+ assertFlagValue(/* key */ "key3", /* expected */ false); // disabled
+ assertFlagValue(/* key */ "key4", /* expected */ false); // disabled
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ private void assertFlagValue(String key, boolean expectedValue) {
+ assertEquals(/* message */"Flag " + key + " value is not " + expectedValue, /* expected */
+ expectedValue, /* actual */ mDeviceConfig.getFlagValue(key));
+ }
+
+
+ private void assertFlagEnabled(String key, boolean expectedValue) {
+ assertEquals(/* message */
+ "Flag " + key + " enabled is not " + expectedValue, /* expected */
+ expectedValue, /* actual */ mDeviceConfig.isBuildTimeFlagEnabled(key));
+ }
+
+ private void updateProperty(String key, Boolean value) {
+ DeviceConfig.setProperty(NAMESPACE_FOR_TEST, key, /* value */
+ value.toString(), /* makeDefault */ false);
+ }
+}
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 1126726..ed0c8ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1452,6 +1452,11 @@
}
});
assertTrue(activity1.isVisible());
+ doReturn(false).when(task1).isTranslucent(null);
+ assertTrue(controller.canApplyDim(task1));
+ doReturn(true).when(task1).isTranslucent(null);
+ assertFalse(controller.canApplyDim(task1));
+
controller.finishTransition(closeTransition);
assertTrue(wasInFinishingTransition[0]);
assertNull(controller.mFinishingTransition);
@@ -2191,8 +2196,11 @@
BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet(
mock(BLASTSyncEngine.TransactionReadyListener.class), "test");
- final boolean[] applyLegacy = new boolean[]{false};
- controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true);
+ final boolean[] applyLegacy = new boolean[2];
+ controller.startLegacySyncOrQueue(legacySync, (deferred) -> {
+ applyLegacy[0] = true;
+ applyLegacy[1] = deferred;
+ });
assertFalse(applyLegacy[0]);
waitUntilHandlersIdle();
@@ -2208,6 +2216,7 @@
assertTrue(transitA.isPlaying());
// legacy sync should start now
assertTrue(applyLegacy[0]);
+ assertTrue(applyLegacy[1]);
// transitB must wait
assertTrue(transitB.isPending());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
new file mode 100644
index 0000000..df11a44
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule;
+import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.platform.test.annotations.Presubmit;
+import android.util.Log;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.TrustedPresentationThresholds;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * TODO (b/287076178): Move these tests to
+ * {@link android.view.surfacecontrol.cts.TrustedPresentationCallbackTest} when API is made public
+ */
+@Presubmit
+public class TrustedPresentationCallbackTest {
+ private static final String TAG = "TrustedPresentationCallbackTest";
+ private static final int STABILITY_REQUIREMENT_MS = 500;
+ private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L;
+
+ private static final float FRACTION_VISIBLE = 0.1f;
+
+ @Rule
+ public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule(
+ TestActivity.class);
+
+ private TestActivity mActivity;
+
+ @Before
+ public void setup() {
+ mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+ }
+
+ @Test
+ public void testAddTrustedPresentationListenerOnWindow() throws InterruptedException {
+ boolean[] results = new boolean[1];
+ CountDownLatch receivedResults = new CountDownLatch(1);
+ TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds(
+ 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds,
+ Runnable::run, inTrustedPresentationState -> {
+ Log.d(TAG, "onTrustedPresentationChanged " + inTrustedPresentationState);
+ results[0] = inTrustedPresentationState;
+ receivedResults.countDown();
+ });
+ t.apply();
+
+ assertTrue("Timed out waiting for results",
+ receivedResults.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(results[0]);
+ }
+
+ @Test
+ public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException {
+ final Object resultsLock = new Object();
+ boolean[] results = new boolean[1];
+ boolean[] receivedResults = new boolean[1];
+ TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds(
+ 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
+ Consumer<Boolean> trustedPresentationCallback = inTrustedPresentationState -> {
+ synchronized (resultsLock) {
+ results[0] = inTrustedPresentationState;
+ receivedResults[0] = true;
+ resultsLock.notify();
+ }
+ };
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds,
+ Runnable::run, trustedPresentationCallback);
+ t.apply();
+
+ synchronized (resultsLock) {
+ if (!receivedResults[0]) {
+ resultsLock.wait(WAIT_TIME_MS);
+ }
+ // Make sure we received the results and not just timed out
+ assertTrue("Timed out waiting for results", receivedResults[0]);
+ assertTrue(results[0]);
+
+ // reset the state
+ receivedResults[0] = false;
+ }
+
+ mActivity.getWindow().getRootSurfaceControl().removeTrustedPresentationCallback(t,
+ trustedPresentationCallback);
+ t.apply();
+
+ synchronized (resultsLock) {
+ if (!receivedResults[0]) {
+ resultsLock.wait(WAIT_TIME_MS);
+ }
+ // Ensure we waited the full time and never received a notify on the result from the
+ // callback.
+ assertFalse("Should never have received a callback", receivedResults[0]);
+ // results shouldn't have changed.
+ assertTrue(results[0]);
+ }
+ }
+
+ public static class TestActivity extends Activity {
+ }
+}
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 f3d8114..4afcd05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -288,6 +288,32 @@
assertEquals(homeWin, dc.mWallpaperController.getWallpaperTarget());
}
+ @Test
+ public void testShowWhenLockedWallpaperTarget() {
+ final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
+ wallpaperWindow.mToken.asWallpaperToken().setShowWhenLocked(true);
+ final WindowState behind = createWindow(null, TYPE_BASE_APPLICATION, "behind");
+ final WindowState topTranslucent = createWindow(null, TYPE_BASE_APPLICATION,
+ "topTranslucent");
+ behind.mAttrs.width = behind.mAttrs.height = topTranslucent.mAttrs.width =
+ topTranslucent.mAttrs.height = WindowManager.LayoutParams.MATCH_PARENT;
+ topTranslucent.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+ doReturn(true).when(behind.mActivityRecord).fillsParent();
+ doReturn(false).when(topTranslucent.mActivityRecord).fillsParent();
+
+ spyOn(mWm.mPolicy);
+ doReturn(true).when(mWm.mPolicy).isKeyguardLocked();
+ doReturn(true).when(mWm.mPolicy).isKeyguardOccluded();
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ // Wallpaper is visible because the show-when-locked activity is translucent.
+ assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(wallpaperWindow));
+
+ behind.mActivityRecord.setShowWhenLocked(true);
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ // Wallpaper is invisible because the lowest show-when-locked activity is opaque.
+ assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(null));
+ }
+
/**
* Tests that the windowing mode of the wallpaper window must always be fullscreen.
*/
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index 7d5be8e..c47d459 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -28,9 +28,9 @@
import android.app.usage.BroadcastResponseStats;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.permission.PermissionManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongArrayQueue;
@@ -94,9 +94,12 @@
private AppStandbyInternal mAppStandby;
private BroadcastResponseStatsLogger mLogger;
private RoleManager mRoleManager;
+ private final Context mContext;
- BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
+ BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby,
+ @NonNull Context context) {
mAppStandby = appStandby;
+ mContext = context;
mLogger = new BroadcastResponseStatsLogger();
}
@@ -305,12 +308,19 @@
boolean doesPackageHoldExemptedPermission(@NonNull String packageName,
@NonNull UserHandle user) {
- final List<String> exemptedPermissions = mAppStandby
- .getBroadcastResponseExemptedPermissions();
+ int uid;
+ try {
+ uid = mContext.getPackageManager().getPackageUidAsUser(
+ packageName, user.getIdentifier());
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ final List<String> exemptedPermissions =
+ mAppStandby.getBroadcastResponseExemptedPermissions();
for (int i = exemptedPermissions.size() - 1; i >= 0; --i) {
final String permissionName = exemptedPermissions.get(i);
- if (PermissionManager.checkPackageNamePermission(permissionName, packageName,
- user.getIdentifier()) == PackageManager.PERMISSION_GRANTED) {
+ if (mContext.checkPermission(permissionName, Process.INVALID_PID, uid)
+ == PackageManager.PERMISSION_GRANTED) {
return true;
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 361b1c0..a8e374f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -178,7 +178,12 @@
}
checkVersionAndBuildLocked();
- indexFilesLocked();
+ // Perform a pruning of older files if there was an upgrade, otherwise do indexing.
+ if (mUpgradePerformed) {
+ prune(currentTimeMillis); // prune performs an indexing when done
+ } else {
+ indexFilesLocked();
+ }
// Delete files that are in the future.
for (TimeSparseArray<AtomicFile> files : mSortedStatFiles) {
@@ -914,26 +919,31 @@
*/
public void prune(final long currentTimeMillis) {
synchronized (mLock) {
+ // prune all files older than 2 years in the yearly directory
mCal.setTimeInMillis(currentTimeMillis);
- mCal.addYears(-3);
+ mCal.addYears(-2);
pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_YEARLY],
mCal.getTimeInMillis());
+ // prune all files older than 6 months in the monthly directory
mCal.setTimeInMillis(currentTimeMillis);
mCal.addMonths(-6);
pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_MONTHLY],
mCal.getTimeInMillis());
+ // prune all files older than 4 weeks in the weekly directory
mCal.setTimeInMillis(currentTimeMillis);
mCal.addWeeks(-4);
pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_WEEKLY],
mCal.getTimeInMillis());
+ // prune all files older than 10 days in the weekly directory
mCal.setTimeInMillis(currentTimeMillis);
mCal.addDays(-10);
pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_DAILY],
mCal.getTimeInMillis());
+ // prune chooser counts for all usage stats older than the defined period
mCal.setTimeInMillis(currentTimeMillis);
mCal.addDays(-SELECTION_LOG_RETENTION_LEN);
for (int i = 0; i < mIntervalDirs.length; ++i) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index cf236dd..43cebe8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -300,7 +300,7 @@
mHandler = new H(BackgroundThread.get().getLooper());
mAppStandby = mInjector.getAppStandbyController(getContext());
- mResponseStatsTracker = new BroadcastResponseStatsTracker(mAppStandby);
+ mResponseStatsTracker = new BroadcastResponseStatsTracker(mAppStandby, getContext());
mAppTimeLimit = new AppTimeLimitController(getContext(),
new AppTimeLimitController.TimeLimitCallbackListener() {
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
index d47ccc7..b7f7c43 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -67,10 +67,6 @@
return GADGET_HAL_V2_0;
}
- @Override
- public void systemReady() {
- }
-
public void serviceDied() {
logAndPrint(Log.ERROR, mPw, "Usb Gadget AIDL hal service died");
synchronized (mGadgetProxyLock) {
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
index 7b52f46..eac796d 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -29,69 +29,6 @@
*/
public interface UsbGadgetHal {
/**
- * Power role: This USB port can act as a source (provide power).
- * @hide
- */
- public static final int HAL_POWER_ROLE_SOURCE = 1;
-
- /**
- * Power role: This USB port can act as a sink (receive power).
- * @hide
- */
- public static final int HAL_POWER_ROLE_SINK = 2;
-
- @IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
- HAL_POWER_ROLE_SOURCE,
- HAL_POWER_ROLE_SINK
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface HalUsbPowerRole{}
-
- /**
- * Data role: This USB port can act as a host (access data services).
- * @hide
- */
- public static final int HAL_DATA_ROLE_HOST = 1;
-
- /**
- * Data role: This USB port can act as a device (offer data services).
- * @hide
- */
- public static final int HAL_DATA_ROLE_DEVICE = 2;
-
- @IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
- HAL_DATA_ROLE_HOST,
- HAL_DATA_ROLE_DEVICE
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface HalUsbDataRole{}
-
- /**
- * This USB port can act as a downstream facing port (host).
- *
- * @hide
- */
- public static final int HAL_MODE_DFP = 1;
-
- /**
- * This USB port can act as an upstream facing port (device).
- *
- * @hide
- */
- public static final int HAL_MODE_UFP = 2;
- @IntDef(prefix = { "HAL_MODE_" }, value = {
- HAL_MODE_DFP,
- HAL_MODE_UFP,
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface HalUsbPortMode{}
-
- /**
- * UsbPortManager would call this when the system is done booting.
- */
- public void systemReady();
-
- /**
* This function is used to query the USB functions included in the
* current USB configuration.
*
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
index 68067d2..80a70dd 100644
--- a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -123,10 +123,6 @@
}
}
- @Override
- public void systemReady() {
- }
-
static boolean isServicePresent(IndentingPrintWriter pw) {
try {
IUsbGadget.getService(true);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
index f98c598..45de058 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
@@ -70,17 +70,17 @@
*
* @hide
*/
- public static final int HAL_MODE_DFP = 1;
+ public static final int HAL_MODE_UFP = 1;
/**
* This USB port can act as an upstream facing port (device).
*
* @hide
*/
- public static final int HAL_MODE_UFP = 2;
+ public static final int HAL_MODE_DFP = 2;
@IntDef(prefix = { "HAL_MODE_" }, value = {
- HAL_MODE_DFP,
HAL_MODE_UFP,
+ HAL_MODE_DFP,
})
@Retention(RetentionPolicy.SOURCE)
@interface HalUsbPortMode{}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 26590c4..a72f780 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -2097,7 +2097,10 @@
* For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
* the {@link PhoneAccount} has {@link PhoneAccount#CAPABILITY_SELF_MANAGED} and the calling app
* does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
- *
+ * <p>
+ * <p>
+ * <b>Note</b>: {@link android.app.Notification.CallStyle} notifications should be posted after
+ * the call is added to Telecom in order for the notification to be non-dismissible.
* @param phoneAccount A {@link PhoneAccountHandle} registered with
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
@@ -2345,7 +2348,10 @@
* {@link PhoneAccount} with the {@link PhoneAccount#CAPABILITY_PLACE_EMERGENCY_CALLS}
* capability, depending on external factors, such as network conditions and Modem/SIM status.
* </p>
- *
+ * <p>
+ * <p>
+ * <b>Note</b>: {@link android.app.Notification.CallStyle} notifications should be posted after
+ * the call is placed in order for the notification to be non-dismissible.
* @param address The address to make the call to.
* @param extras Bundle of extras to use with the call.
*/
@@ -2679,9 +2685,11 @@
/**
* Add a call to the Android system service Telecom. This allows the system to start tracking an
- * incoming or outgoing call with the specified {@link CallAttributes}. Once the call is ready
- * to be disconnected, use the {@link CallControl#disconnect(DisconnectCause, Executor,
- * OutcomeReceiver)} which is provided by the {@code pendingControl#onResult(CallControl)}.
+ * incoming or outgoing call with the specified {@link CallAttributes}. Once a call is added,
+ * a {@link android.app.Notification.CallStyle} notification should be posted and when the
+ * call is ready to be disconnected, use {@link CallControl#disconnect(DisconnectCause,
+ * Executor, OutcomeReceiver)} which is provided by the
+ * {@code pendingControl#onResult(CallControl)}.
* <p>
* <p>
* <p>
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5b1c6b1..27b81d8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -570,6 +570,13 @@
"editable_voicemail_number_bool";
/**
+ * Determine whether the voicemail number in Settings is hidden.
+ * @hide
+ */
+ public static final String KEY_HIDE_VOICEMAIL_NUMBER_SETTING_BOOL =
+ "hide_voicemail_number_setting_bool";
+
+ /**
* Determine whether the voicemail notification is persistent in the notification bar. If true,
* the voicemail notifications cannot be dismissed from the notification bar.
*/
@@ -9730,6 +9737,27 @@
public static final String KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY =
"iwlan_handover_policy_string_array";
+ /**
+ * Score table for {@link TelephonyManager#MOBILE_DATA_POLICY_AUTO_DATA_SWITCH}. The score is
+ * used in conjunction with a tolerance value defined in resource config
+ * {@code auto_data_switch_score_tolerance}, greater than which device will switch to the sub
+ * with higher score.
+ * Possible keys are network type name string(also see {@link #KEY_BANDWIDTH_STRING_ARRAY}).
+ * Value should be "score_level_0, score_level_1, score_level_2, score_level_3,score_level_4".
+ * Each network type must have 5 scores correspond to {@link CellSignalStrength}, where score is
+ * a non-negative integer. A score of 0 is treated the same as data out of service.
+ *
+ * For NR (5G), the following network names should be used:
+ * - NR_NSA: NR NSA, sub-6 frequencies
+ * - NR_NSA_MMWAVE: NR NSA, mmwave frequencies
+ * - NR_SA: NR SA, sub-6 frequencies
+ * - NR_SA_MMWAVE: NR SA, mmwave frequencies
+ *
+ * @hide
+ */
+ public static final String KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_BUNDLE =
+ "auto_data_switch_rat_signal_score_string_bundle";
+
/** The default value for every variable. */
private static final PersistableBundle sDefaults;
@@ -9834,6 +9862,7 @@
sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL, true);
sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL, false);
+ sDefaults.putBoolean(KEY_HIDE_VOICEMAIL_NUMBER_SETTING_BOOL, false);
sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
@@ -10404,6 +10433,51 @@
sDefaults.putStringArray(KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{
"source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, "
+ "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"});
+ PersistableBundle auto_data_switch_rat_signal_score_string_bundle = new PersistableBundle();
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "NR_SA_MMWAVE", new int[]{10000, 13227, 16000, 18488, 20017});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "NR_NSA_MMWAVE", new int[]{8000, 10227, 12488, 15017, 15278});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "LTE", new int[]{3731, 5965, 8618, 11179, 13384});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "NR_SA", new int[]{5288, 6795, 6955, 7562, 9713});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "NR_NSA", new int[]{5463, 6827, 8029, 9007, 9428});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "UMTS", new int[]{100, 169, 183, 192, 300});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "eHRPD", new int[]{10, 400, 600, 800, 1000});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "TD_SCDMA", new int[]{1, 100, 500, 1000});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "iDEN", new int[]{1, 2, 10, 50, 100});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "EvDo_B", new int[]{1000, 1495, 2186, 2532, 2600});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "HSPA+", new int[]{1619, 2500, 3393, 4129, 4212});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "HSPA", new int[]{1000, 1495, 2186, 2532, 2544});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "HSUPA", new int[]{1500, 1919, 2132, 2362, 2704});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "HSDPA", new int[]{1500, 1732, 4000, 7000, 8000});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "EvDo_A", new int[]{600, 840, 1200, 1300, 1400});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "EvDo_0", new int[]{300, 600, 1000, 1500, 2000});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "1xRTT", new int[]{50, 60, 70, 80});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "EDGE", new int[]{154, 169, 183, 192, 267});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "GPRS", new int[]{15, 30, 40, 45, 50});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "CDMA", new int[]{1, 50, 100, 300, 2000});
+ auto_data_switch_rat_signal_score_string_bundle.putIntArray(
+ "GSM", new int[]{1, 2, 10, 50, 100});
+ sDefaults.putPersistableBundle(KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_BUNDLE,
+ auto_data_switch_rat_signal_score_string_bundle);
sDefaults.putInt(KEY_CELLULAR_USAGE_SETTING_INT,
SubscriptionManager.USAGE_SETTING_UNKNOWN);
// Default data stall recovery configurations.
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index 65c2146..3285bc3 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,6 +26,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
/**
* Defines a request to perform a network scan.
@@ -108,6 +111,7 @@
private int mIncrementalResultsPeriodicity;
/** Describes the radio access technologies with bands or channels that need to be scanned. */
+ @Nullable
private RadioAccessSpecifier[] mSpecifiers;
/**
@@ -117,6 +121,7 @@
* If list not sent, search to be completed till end and all PLMNs found to be reported.
* Max size of array is MAX_MCC_MNC_LIST_SIZE
*/
+ @NonNull
private ArrayList<String> mMccMncs;
/**
@@ -240,27 +245,20 @@
}
@Override
- public boolean equals (Object o) {
- NetworkScanRequest nsr;
+ public boolean equals(Object other) {
+ if (this == other) return true;
- try {
- nsr = (NetworkScanRequest) o;
- } catch (ClassCastException ex) {
- return false;
- }
+ if (!(other instanceof NetworkScanRequest)) return false;
- if (o == null) {
- return false;
- }
+ NetworkScanRequest nsr = (NetworkScanRequest) other;
- return (mScanType == nsr.mScanType
+ return mScanType == nsr.mScanType
&& Arrays.equals(mSpecifiers, nsr.mSpecifiers)
&& mSearchPeriodicity == nsr.mSearchPeriodicity
&& mMaxSearchTime == nsr.mMaxSearchTime
&& mIncrementalResults == nsr.mIncrementalResults
&& mIncrementalResultsPeriodicity == nsr.mIncrementalResultsPeriodicity
- && (((mMccMncs != null)
- && mMccMncs.equals(nsr.mMccMncs))));
+ && Objects.equals(mMccMncs, nsr.mMccMncs);
}
@Override
diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
index 0ab3dfe..f8a1ec9 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
+++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
@@ -22,9 +22,6 @@
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="DynamicCodeLoggerIntegrationTests"/>
- <!-- This test make uses of the event log, make sure we capture it. -->
- <option name="logcat-options" value="-b all" />
-
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.dynamiccodeloggertest"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index efd9b00..7c9c05d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -21,7 +21,7 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerBuilderProvider
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
@@ -37,7 +37,7 @@
abstract class BaseTest
@JvmOverloads
constructor(
- protected val flicker: FlickerTest,
+ protected val flicker: LegacyFlickerTest,
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
) {
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 ed9e14f..1fdbe7f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -23,14 +23,14 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.IComponentNameMatcher
import android.tools.common.traces.wm.WindowManagerTrace
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.WindowUtils
/**
* Checks that [ComponentNameMatcher.STATUS_BAR] window is visible and above the app windows in all
* WM trace entries
*/
-fun FlickerTest.statusBarWindowIsAlwaysVisible() {
+fun LegacyFlickerTest.statusBarWindowIsAlwaysVisible() {
assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.STATUS_BAR) }
}
@@ -38,7 +38,7 @@
* Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows in all WM
* trace entries
*/
-fun FlickerTest.navBarWindowIsAlwaysVisible() {
+fun LegacyFlickerTest.navBarWindowIsAlwaysVisible() {
assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
}
@@ -46,7 +46,7 @@
* Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
* start and end of the WM trace
*/
-fun FlickerTest.navBarWindowIsVisibleAtStartAndEnd() {
+fun LegacyFlickerTest.navBarWindowIsVisibleAtStartAndEnd() {
this.navBarWindowIsVisibleAtStart()
this.navBarWindowIsVisibleAtEnd()
}
@@ -55,7 +55,7 @@
* Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
* start of the WM trace
*/
-fun FlickerTest.navBarWindowIsVisibleAtStart() {
+fun LegacyFlickerTest.navBarWindowIsVisibleAtStart() {
assertWmStart { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
}
@@ -63,7 +63,7 @@
* Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the end
* of the WM trace
*/
-fun FlickerTest.navBarWindowIsVisibleAtEnd() {
+fun LegacyFlickerTest.navBarWindowIsVisibleAtEnd() {
assertWmEnd { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
}
@@ -71,7 +71,7 @@
* Checks that [ComponentNameMatcher.TASK_BAR] window is visible and above the app windows in all WM
* trace entries
*/
-fun FlickerTest.taskBarWindowIsAlwaysVisible() {
+fun LegacyFlickerTest.taskBarWindowIsAlwaysVisible() {
assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) }
}
@@ -79,7 +79,7 @@
* Checks that [ComponentNameMatcher.TASK_BAR] window is visible and above the app windows in all WM
* trace entries
*/
-fun FlickerTest.taskBarWindowIsVisibleAtEnd() {
+fun LegacyFlickerTest.taskBarWindowIsVisibleAtEnd() {
assertWmEnd { this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) }
}
@@ -93,43 +93,45 @@
* @param allStates if all states should be checked, othersie, just initial and final
*/
@JvmOverloads
-fun FlickerTest.entireScreenCovered(allStates: Boolean = true) {
+fun LegacyFlickerTest.entireScreenCovered(allStates: Boolean = true) {
if (allStates) {
assertLayers {
this.invoke("entireScreenCovered") { entry ->
- entry.entry.displays.filter { it.isOn }.forEach { display ->
- entry.visibleRegion().coversAtLeast(display.layerStackSpace)
- }
+ entry.entry.displays
+ .filter { it.isOn }
+ .forEach { display ->
+ entry.visibleRegion().coversAtLeast(display.layerStackSpace)
+ }
}
}
} else {
assertLayersStart {
- this.entry.displays.filter { it.isOn }.forEach { display ->
- this.visibleRegion().coversAtLeast(display.layerStackSpace)
- }
+ this.entry.displays
+ .filter { it.isOn }
+ .forEach { display -> this.visibleRegion().coversAtLeast(display.layerStackSpace) }
}
assertLayersEnd {
- this.entry.displays.filter { it.isOn }.forEach { display ->
- this.visibleRegion().coversAtLeast(display.layerStackSpace)
- }
+ this.entry.displays
+ .filter { it.isOn }
+ .forEach { display -> this.visibleRegion().coversAtLeast(display.layerStackSpace) }
}
}
}
/** Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the start of the SF trace */
-fun FlickerTest.navBarLayerIsVisibleAtStart() {
+fun LegacyFlickerTest.navBarLayerIsVisibleAtStart() {
assertLayersStart { this.isVisible(ComponentNameMatcher.NAV_BAR) }
}
/** Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the end of the SF trace */
-fun FlickerTest.navBarLayerIsVisibleAtEnd() {
+fun LegacyFlickerTest.navBarLayerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(ComponentNameMatcher.NAV_BAR) }
}
/**
* Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the start and end of the SF trace
*/
-fun FlickerTest.navBarLayerIsVisibleAtStartAndEnd() {
+fun LegacyFlickerTest.navBarLayerIsVisibleAtStartAndEnd() {
this.navBarLayerIsVisibleAtStart()
this.navBarLayerIsVisibleAtEnd()
}
@@ -137,18 +139,18 @@
/**
* Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the start and end of the SF trace
*/
-fun FlickerTest.taskBarLayerIsVisibleAtStartAndEnd() {
+fun LegacyFlickerTest.taskBarLayerIsVisibleAtStartAndEnd() {
this.taskBarLayerIsVisibleAtStart()
this.taskBarLayerIsVisibleAtEnd()
}
/** Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the start of the SF trace */
-fun FlickerTest.taskBarLayerIsVisibleAtStart() {
+fun LegacyFlickerTest.taskBarLayerIsVisibleAtStart() {
assertLayersStart { this.isVisible(ComponentNameMatcher.TASK_BAR) }
}
/** Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the end of the SF trace */
-fun FlickerTest.taskBarLayerIsVisibleAtEnd() {
+fun LegacyFlickerTest.taskBarLayerIsVisibleAtEnd() {
assertLayersEnd { this.isVisible(ComponentNameMatcher.TASK_BAR) }
}
@@ -156,7 +158,7 @@
* Checks that [ComponentNameMatcher.STATUS_BAR] layer is visible at the start and end of the SF
* trace
*/
-fun FlickerTest.statusBarLayerIsVisibleAtStartAndEnd() {
+fun LegacyFlickerTest.statusBarLayerIsVisibleAtStartAndEnd() {
assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
}
@@ -165,7 +167,7 @@
* Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the start of
* the SF trace
*/
-fun FlickerTest.navBarLayerPositionAtStart() {
+fun LegacyFlickerTest.navBarLayerPositionAtStart() {
assertLayersStart {
val display =
this.entry.displays.firstOrNull { !it.isVirtual } ?: error("There is no display!")
@@ -180,7 +182,7 @@
* Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the end of
* the SF trace
*/
-fun FlickerTest.navBarLayerPositionAtEnd() {
+fun LegacyFlickerTest.navBarLayerPositionAtEnd() {
assertLayersEnd {
val display =
this.entry.displays.minByOrNull { it.id }
@@ -196,7 +198,7 @@
* Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the start and
* end of the SF trace
*/
-fun FlickerTest.navBarLayerPositionAtStartAndEnd() {
+fun LegacyFlickerTest.navBarLayerPositionAtStartAndEnd() {
navBarLayerPositionAtStart()
navBarLayerPositionAtEnd()
}
@@ -205,7 +207,7 @@
* Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the start
* of the SF trace
*/
-fun FlickerTest.statusBarLayerPositionAtStart(
+fun LegacyFlickerTest.statusBarLayerPositionAtStart(
wmTrace: WindowManagerTrace? = this.reader.readWmTrace()
) {
// collect navbar position for the equivalent WM state
@@ -221,7 +223,7 @@
* Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the end of
* the SF trace
*/
-fun FlickerTest.statusBarLayerPositionAtEnd(
+fun LegacyFlickerTest.statusBarLayerPositionAtEnd(
wmTrace: WindowManagerTrace? = this.reader.readWmTrace()
) {
// collect navbar position for the equivalent WM state
@@ -237,7 +239,7 @@
* Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the start
* and end of the SF trace
*/
-fun FlickerTest.statusBarLayerPositionAtStartAndEnd() {
+fun LegacyFlickerTest.statusBarLayerPositionAtStartAndEnd() {
statusBarLayerPositionAtStart()
statusBarLayerPositionAtEnd()
}
@@ -246,7 +248,9 @@
* Asserts that the visibleRegion of the [ComponentNameMatcher.SNAPSHOT] layer can cover the
* visibleRegion of the given app component exactly
*/
-fun FlickerTest.snapshotStartingWindowLayerCoversExactlyOnApp(component: IComponentNameMatcher) {
+fun LegacyFlickerTest.snapshotStartingWindowLayerCoversExactlyOnApp(
+ component: IComponentNameMatcher
+) {
assertLayers {
invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
val snapshotLayers =
@@ -307,7 +311,7 @@
* otherwise we won't and the layer must appear immediately.
* ```
*/
-fun FlickerTest.replacesLayer(
+fun LegacyFlickerTest.replacesLayer(
originalLayer: IComponentNameMatcher,
newLayer: IComponentNameMatcher,
ignoreEntriesWithRotationLayer: Boolean = false,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
index 7ef4d93..45cd65d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -16,12 +16,12 @@
package com.android.server.wm.flicker.activityembedding
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.Before
-abstract class ActivityEmbeddingTestBase(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(flicker) {
val testApp = ActivityEmbeddingAppHelper(instrumentation)
@Before
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt
new file mode 100644
index 0000000..4bc17ed
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/RTLStartSecondaryWithPlaceholderTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a placeholder split over a normal split, both splits are configured in RTL.
+ *
+ * Setup: From A launch a split in RTL - resulting in B|A. Transitions: From A start
+ * PlaceholderPrimary, which is configured to launch with PlaceholderSecondary in RTL. Expect split
+ * PlaceholderSecondary|PlaceholderPrimary covering split B|A.
+ *
+ * To run this test: `atest FlickerTests:RTLStartSecondaryWithPlaceholderTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class RTLStartSecondaryWithPlaceholderTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+ testApp.launchViaIntent(wmHelper)
+ testApp.launchSecondaryActivityRTL(wmHelper)
+ }
+ transitions { testApp.launchPlaceholderSplitRTL(wmHelper) }
+ teardown {
+ tapl.goHome()
+ testApp.exit(wmHelper)
+ }
+ }
+
+ /**
+ * Main activity and Secondary activity will become invisible because they are covered by
+ * PlaceholderPrimary activity and PlaceholderSecondary activity.
+ */
+ @Presubmit
+ @Test
+ fun assertWindowVisibilities() {
+ flicker.assertWm {
+ isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ flicker.assertWm {
+ isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ flicker.assertWm {
+ isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ .then()
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ }
+ flicker.assertWm {
+ isAppWindowInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ .then()
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ }
+ }
+
+ /**
+ * Main activity and Secondary activity will become invisible because they are covered by
+ * PlaceholderPrimary activity and PlaceholderSecondary activity.
+ */
+ @Presubmit
+ @Test
+ fun assertLayerVisibilities() {
+ flicker.assertLayers {
+ this.isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ flicker.assertLayers {
+ this.isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ flicker.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ }
+ flicker.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ }
+ }
+
+ /** Main activity and Secondary activity split is in right-to-left layout direction. */
+ @Presubmit
+ @Test
+ fun assertWMRTLBeforeTransition() {
+ flicker.assertWmStart {
+ val mainActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val secondaryActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
+ // secondary activity is on the left, main activity is on the right.
+ check { "isRTLBeforeTransition" }
+ .that(mainActivityRegion.region.bounds.left)
+ .isEqual(secondaryActivityRegion.region.bounds.right)
+ }
+ }
+
+ /** Main activity and Secondary activity split is in right-to-left layout direction. */
+ @Presubmit
+ @Test
+ fun assertLayerRTLBeforeTransition() {
+ flicker.assertLayersStart {
+ val mainActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val secondaryActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
+ // secondary activity is on the left, main activity is on the right.
+ check { "isRTLBeforeTransition" }
+ .that(mainActivityRegion.region.bounds.left)
+ .isEqual(secondaryActivityRegion.region.bounds.right)
+ }
+ }
+
+ /**
+ * PlaceholderPrimary activity and PlaceholderSecondary activity split are in right-to-left
+ * layout direction.
+ */
+ @Presubmit
+ @Test
+ fun assertWMRTLAfterTransition() {
+ flicker.assertWmEnd {
+ val mainActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val secondaryActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
+ // secondary activity is on the left, main activity is on the right.
+ check { "isRTLBeforeTransition" }
+ .that(mainActivityRegion.region.bounds.left)
+ .isEqual(secondaryActivityRegion.region.bounds.right)
+ }
+ }
+
+ /**
+ * PlaceholderPrimary activity and PlaceholderSecondary activity split are in right-to-left
+ * layout direction.
+ */
+ @Presubmit
+ @Test
+ fun assertLayerRTLAfterTransition() {
+ flicker.assertLayersEnd {
+ val mainActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ val secondaryActivityRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ mainActivityRegion.notOverlaps(secondaryActivityRegion.region)
+ // Placeholder secondary activity is on the left, placeholder primary activity is on the
+ // right.
+ check { "isRTLAfterTransition" }
+ .that(mainActivityRegion.region.bounds.left)
+ .isEqual(secondaryActivityRegion.region.bounds.right)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index c0c738b..7a582f7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
@@ -34,8 +34,8 @@
/**
* Test closing a secondary activity in a split.
*
- * Setup: Launch A|B in split with B being the secondary activity.
- * Transitions: Finish B and expect A to become fullscreen.
+ * Setup: Launch A|B in split with B being the secondary activity. Transitions: Finish B and expect
+ * A to become fullscreen.
*
* To run this test: `atest FlickerTests:CloseSecondaryActivityInSplitTest`
*/
@@ -43,95 +43,93 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseSecondaryActivityInSplitTest(flicker: FlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class CloseSecondaryActivityInSplitTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
- override val transition: FlickerBuilder.() -> Unit = {
- setup {
- tapl.setExpectedRotationCheckEnabled(false)
- // Launches fullscreen A.
- testApp.launchViaIntent(wmHelper)
- // Launches a split A|B and waits for both activities to show.
- testApp.launchSecondaryActivity(wmHelper)
- // Get fullscreen bounds
- startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds ?:
- error("Can't get display bounds")
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+ // Launches fullscreen A.
+ testApp.launchViaIntent(wmHelper)
+ // Launches a split A|B and waits for both activities to show.
+ testApp.launchSecondaryActivity(wmHelper)
+ // Get fullscreen bounds
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds
+ ?: error("Can't get display bounds")
+ }
+ transitions {
+ // Finish secondary activity B.
+ testApp.finishSecondaryActivity(wmHelper)
+ // Expect the main activity A to expand into fullscreen.
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+ teardown {
+ tapl.goHome()
+ testApp.exit(wmHelper)
+ }
}
- transitions {
- // Finish secondary activity B.
- testApp.finishSecondaryActivity(wmHelper)
- // Expect the main activity A to expand into fullscreen.
- wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
- }
- teardown {
- tapl.goHome()
- testApp.exit(wmHelper)
- }
- }
- /** Main activity is always visible and becomes fullscreen in the end. */
- @Presubmit
- @Test
- fun mainActivityWindowBecomesFullScreen() {
- flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
- flicker.assertWmEnd {
- this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .coversExactly(startDisplayBounds)
+ /** Main activity is always visible and becomes fullscreen in the end. */
+ @Presubmit
+ @Test
+ fun mainActivityWindowBecomesFullScreen() {
+ flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ flicker.assertWmEnd {
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .coversExactly(startDisplayBounds)
+ }
}
- }
- /** Main activity surface is animated from split to fullscreen. */
- @Presubmit
- @Test
- fun mainActivityLayerIsAlwaysVisible() {
- flicker.assertLayers {
- isVisible(
- ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT.or(
- ComponentNameMatcher.TRANSITION_SNAPSHOT
- )
- )
+ /** Main activity surface is animated from split to fullscreen. */
+ @Presubmit
+ @Test
+ fun mainActivityLayerIsAlwaysVisible() {
+ flicker.assertLayers {
+ isVisible(
+ ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT.or(
+ ComponentNameMatcher.TRANSITION_SNAPSHOT
+ )
+ )
+ }
+ flicker.assertLayersEnd {
+ isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .isInvisible(ComponentNameMatcher.TRANSITION_SNAPSHOT)
+ }
}
- flicker.assertLayersEnd {
- isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .isInvisible(ComponentNameMatcher.TRANSITION_SNAPSHOT)
- }
- }
- /** Secondary activity should destroy and become invisible. */
- @Presubmit
- @Test
- fun secondaryActivityWindowFinishes() {
- flicker.assertWm {
- contains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .then()
- .notContains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ /** Secondary activity should destroy and become invisible. */
+ @Presubmit
+ @Test
+ fun secondaryActivityWindowFinishes() {
+ flicker.assertWm {
+ contains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .notContains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
}
- }
- @Presubmit
- @Test
- fun secondaryActivityLayerFinishes() {
- flicker.assertLayers {
- isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .then()
- .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ @Presubmit
+ @Test
+ fun secondaryActivityLayerFinishes() {
+ flicker.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
}
- }
- companion object {
- /** {@inheritDoc} */
- private var startDisplayBounds = Rect.EMPTY
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
- }
- }
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index 00316ea..48aaebd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -16,11 +16,13 @@
package com.android.server.wm.flicker.activityembedding
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
+import android.tools.common.datatypes.Rect
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
@@ -28,14 +30,12 @@
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-import android.tools.common.datatypes.Rect
/**
* Test launching an activity with AlwaysExpand rule.
*
- * Setup: Launch A|B in split with B being the secondary activity.
- * Transitions:
- * A start C with alwaysExpand=true, expect C to launch in fullscreen and cover split A|B.
+ * Setup: Launch A|B in split with B being the secondary activity. Transitions: A start C with
+ * alwaysExpand=true, expect C to launch in fullscreen and cover split A|B.
*
* To run this test: `atest FlickerTests:MainActivityStartsSecondaryWithAlwaysExpandTest`
*/
@@ -43,98 +43,109 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MainActivityStartsSecondaryWithAlwaysExpandTest(flicker: FlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class MainActivityStartsSecondaryWithAlwaysExpandTest(flicker: LegacyFlickerTest) :
+ ActivityEmbeddingTestBase(flicker) {
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit = {
- setup {
- tapl.setExpectedRotationCheckEnabled(false)
- // Launch a split
- testApp.launchViaIntent(wmHelper)
- testApp.launchSecondaryActivity(wmHelper)
- startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
- }
- transitions {
- // Launch C with alwaysExpand
- testApp.launchAlwaysExpandActivity(wmHelper)
- }
- teardown {
- tapl.goHome()
- testApp.exit(wmHelper)
- }
- }
-
- /** Transition begins with a split. */
- @Presubmit
- @Test
- fun startsWithSplit() {
- flicker.assertWmStart {
- this.isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- }
- flicker.assertWmStart {
- this.isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- }
- }
-
-
- /** Main activity should become invisible after being covered by always expand activity. */
- @Presubmit
- @Test
- fun mainActivityLayerBecomesInvisible() {
- flicker.assertLayers {
- isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- .then()
- .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- }
- }
-
- /** Secondary activity should become invisible after being covered by always expand activity. */
- @Presubmit
- @Test
- fun secondaryActivityLayerBecomesInvisible() {
- flicker.assertLayers {
- isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- .then()
- .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- }
- }
-
- /** At the end of transition always expand activity is in fullscreen. */
- @Presubmit
- @Test
- fun endsWithAlwaysExpandActivityCoveringFullScreen() {
- flicker.assertWmEnd {
- this.visibleRegion(ActivityEmbeddingAppHelper.ALWAYS_EXPAND_ACTIVITY_COMPONENT)
- .coversExactly(startDisplayBounds)
- }
- }
-
- /** Always expand activity is on top of the split. */
- @Presubmit
- @Test
- fun endsWithAlwaysExpandActivityOnTop() {
- flicker.assertWmEnd {
- this.isAppWindowOnTop(
- ActivityEmbeddingAppHelper.ALWAYS_EXPAND_ACTIVITY_COMPONENT)
- }
- }
-
- companion object {
/** {@inheritDoc} */
- private var startDisplayBounds = Rect.EMPTY
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+ // Launch a split
+ testApp.launchViaIntent(wmHelper)
+ testApp.launchSecondaryActivity(wmHelper)
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
+ }
+ transitions {
+ // Launch C with alwaysExpand
+ testApp.launchAlwaysExpandActivity(wmHelper)
+ }
+ teardown {
+ tapl.goHome()
+ testApp.exit(wmHelper)
+ }
}
- }
-}
+ @FlakyTest(bugId = 286952194)
+ @Presubmit
+ @Test
+ override fun navBarWindowIsVisibleAtStartAndEnd() {}
+
+ @FlakyTest(bugId = 286952194)
+ @Presubmit
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() {}
+
+ @FlakyTest(bugId = 286952194)
+ @Presubmit
+ @Test
+ override fun statusBarLayerPositionAtStartAndEnd() {}
+
+ /** Transition begins with a split. */
+ @Presubmit
+ @Test
+ fun startsWithSplit() {
+ flicker.assertWmStart {
+ this.isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ flicker.assertWmStart {
+ this.isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** Main activity should become invisible after being covered by always expand activity. */
+ @Presubmit
+ @Test
+ fun mainActivityLayerBecomesInvisible() {
+ flicker.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** Secondary activity should become invisible after being covered by always expand activity. */
+ @Presubmit
+ @Test
+ fun secondaryActivityLayerBecomesInvisible() {
+ flicker.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** At the end of transition always expand activity is in fullscreen. */
+ @Presubmit
+ @Test
+ fun endsWithAlwaysExpandActivityCoveringFullScreen() {
+ flicker.assertWmEnd {
+ this.visibleRegion(ActivityEmbeddingAppHelper.ALWAYS_EXPAND_ACTIVITY_COMPONENT)
+ .coversExactly(startDisplayBounds)
+ }
+ }
+
+ /** Always expand activity is on top of the split. */
+ @FlakyTest(bugId = 286952194)
+ @Presubmit
+ @Test
+ fun endsWithAlwaysExpandActivityOnTop() {
+ flicker.assertWmEnd {
+ this.isAppWindowOnTop(ActivityEmbeddingAppHelper.ALWAYS_EXPAND_ACTIVITY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index ed17059..27a5bd0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -19,8 +19,8 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
@@ -39,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenActivityEmbeddingPlaceholderSplitTest(flicker: FlickerTest) :
+class OpenActivityEmbeddingPlaceholderSplitTest(flicker: LegacyFlickerTest) :
ActivityEmbeddingTestBase(flicker) {
/** {@inheritDoc} */
@@ -117,13 +117,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 8638288..16dbfce 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -20,8 +20,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
@@ -39,7 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenActivityEmbeddingSecondaryToSplitTest(flicker: FlickerTest) :
+class OpenActivityEmbeddingSecondaryToSplitTest(flicker: LegacyFlickerTest) :
ActivityEmbeddingTestBase(flicker) {
/** {@inheritDoc} */
@@ -110,13 +110,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 39ae8e2..856c9e2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -18,13 +18,13 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import com.android.server.wm.flicker.rotation.RotationTransition
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import com.android.server.wm.flicker.rotation.RotationTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,8 +34,8 @@
/**
* Tests rotating two activities in an Activity Embedding split.
*
- * Setup: Launch A|B in split with B being the secondary activity.
- * Transitions: Rotate display, and expect A and B to split evenly in new rotation.
+ * Setup: Launch A|B in split with B being the secondary activity. Transitions: Rotate display, and
+ * expect A and B to split evenly in new rotation.
*
* To run this test: `atest FlickerTests:RotateSplitNoChangeTest`
*/
@@ -43,100 +43,104 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class RotateSplitNoChangeTest(flicker: FlickerTest) : RotationTransition(flicker) {
+open class RotateSplitNoChangeTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
- override val testApp = ActivityEmbeddingAppHelper(instrumentation)
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- testApp.launchViaIntent(wmHelper)
- testApp.launchSecondaryActivity(wmHelper)
- }
- }
+ override val testApp = ActivityEmbeddingAppHelper(instrumentation)
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
+ setup {
+ testApp.launchViaIntent(wmHelper)
+ testApp.launchSecondaryActivity(wmHelper)
+ }
+ }
- /**
- * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
- * flicker, and disappears before the transition is complete
- */
- @Presubmit
- @Test
- fun rotationLayerAppearsAndVanishes() {
- flicker.assertLayers {
- this.isVisible(testApp)
- .then()
- .isVisible(ComponentNameMatcher.ROTATION)
- .then()
- .isVisible(testApp)
- .isInvisible(ComponentNameMatcher.ROTATION)
- }
- }
-
- /**
- * Overrides inherited assertion because in AE Split, the main and secondary activity are separate
- * layers, each covering up exactly half of the display.
- */
- @Presubmit
- @Test
- override fun appLayerRotates_StartingPos() {
- flicker.assertLayersStart {
- this.entry.displays.map { display ->
- val leftLayerRegion = this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- val rightLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- // Compare dimensions of two splits, given we're using default split attributes,
- // both activities take up the same visible size on the display.
- check{"height"}.that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
- check{"width"}.that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
- leftLayerRegion.notOverlaps(rightLayerRegion.region)
- // Layers of two activities sum to be fullscreen size on display.
- leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
- }
- }
- }
-
- /**
- * Verifies dimensions of both split activities hold their invariance after transition too.
- */
- @Presubmit
- @Test
- override fun appLayerRotates_EndingPos() {
- flicker.assertLayersEnd {
- this.entry.displays.map { display ->
- val leftLayerRegion = this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- val rightLayerRegion =
- this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- check{"height"}.that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
- check{"width"}.that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
- leftLayerRegion.notOverlaps(rightLayerRegion.region)
- leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
- }
- }
- }
-
- /** Both activities in split should remain visible during rotation. */
- @Presubmit
- @Test
- fun bothActivitiesAreAlwaysVisible() {
- flicker.assertWm {
- isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
- }
- flicker.assertWm {
- isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
- }
- }
-
- companion object {
/**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
+ * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
+ * flicker, and disappears before the transition is complete
*/
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
+ @Presubmit
+ @Test
+ fun rotationLayerAppearsAndVanishes() {
+ flicker.assertLayers {
+ this.isVisible(testApp)
+ .then()
+ .isVisible(ComponentNameMatcher.ROTATION)
+ .then()
+ .isVisible(testApp)
+ .isInvisible(ComponentNameMatcher.ROTATION)
+ }
}
- }
-}
\ No newline at end of file
+
+ /**
+ * Overrides inherited assertion because in AE Split, the main and secondary activity are
+ * separate layers, each covering up exactly half of the display.
+ */
+ @Presubmit
+ @Test
+ override fun appLayerRotates_StartingPos() {
+ flicker.assertLayersStart {
+ this.entry.displays.map { display ->
+ val leftLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ // Compare dimensions of two splits, given we're using default split attributes,
+ // both activities take up the same visible size on the display.
+ check { "height" }
+ .that(leftLayerRegion.region.height)
+ .isEqual(rightLayerRegion.region.height)
+ check { "width" }
+ .that(leftLayerRegion.region.width)
+ .isEqual(rightLayerRegion.region.width)
+ leftLayerRegion.notOverlaps(rightLayerRegion.region)
+ // Layers of two activities sum to be fullscreen size on display.
+ leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /** Verifies dimensions of both split activities hold their invariance after transition too. */
+ @Presubmit
+ @Test
+ override fun appLayerRotates_EndingPos() {
+ flicker.assertLayersEnd {
+ this.entry.displays.map { display ->
+ val leftLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightLayerRegion =
+ this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ check { "height" }
+ .that(leftLayerRegion.region.height)
+ .isEqual(rightLayerRegion.region.height)
+ check { "width" }
+ .that(leftLayerRegion.region.width)
+ .isEqual(rightLayerRegion.region.width)
+ leftLayerRegion.notOverlaps(rightLayerRegion.region)
+ leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /** Both activities in split should remain visible during rotation. */
+ @Presubmit
+ @Test
+ fun bothActivitiesAreAlwaysVisible() {
+ flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ flicker.assertWm {
+ isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.rotationTests()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 10b71ff..865d5b4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -20,8 +20,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -76,7 +76,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseAppBackButtonTest(flicker: FlickerTest) : CloseAppTransition(flicker) {
+open class CloseAppBackButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -96,13 +96,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt
index 9fa84019..c108633 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,18 +29,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTestCfArm(flicker: FlickerTest) : CloseAppBackButtonTest(flicker) {
+class CloseAppBackButtonTestCfArm(flicker: LegacyFlickerTest) : CloseAppBackButtonTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): List<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index e5bd350..ea9710c6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -20,8 +20,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
@@ -76,7 +76,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseAppHomeButtonTest(flicker: FlickerTest) : CloseAppTransition(flicker) {
+open class CloseAppHomeButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -101,8 +101,6 @@
/** Creates the test configurations. */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt
index 136995a..d65555a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,13 +29,11 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTestCfArm(flicker: FlickerTest) : CloseAppHomeButtonTest(flicker) {
+class CloseAppHomeButtonTestCfArm(flicker: LegacyFlickerTest) : CloseAppHomeButtonTest(flicker) {
companion object {
/** Creates the test configurations. */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 4570fa2..9be9cb7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -20,7 +20,7 @@
import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
@@ -28,7 +28,7 @@
import org.junit.Test
/** Base test class for transitions that close an app back to the launcher screen */
-abstract class CloseAppTransition(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class CloseAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index a21965e..351eb1e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -75,7 +75,7 @@
.StateSyncBuilder()
.withActivityRemoved(SECONDARY_ACTIVITY_COMPONENT)
.waitForAndVerify()
- }
+ }
/**
* Clicks the button to launch a secondary activity with alwaysExpand enabled, which will launch
@@ -83,21 +83,40 @@
*/
fun launchAlwaysExpandActivity(wmHelper: WindowManagerStateHelper) {
val launchButton =
- uiDevice.wait(
- Until.findObject(
- By.res(getPackage(),
- "launch_always_expand_activity_button")),
- FIND_TIMEOUT
- )
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_always_expand_activity_button")),
+ FIND_TIMEOUT
+ )
require(launchButton != null) {
"Can't find launch always expand activity button on screen."
}
launchButton.click()
wmHelper
- .StateSyncBuilder()
- .withActivityState(ALWAYS_EXPAND_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
- .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_PAUSED)
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withActivityState(ALWAYS_EXPAND_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_PAUSED)
+ .waitForAndVerify()
+ }
+
+ /**
+ * Clicks the button to launch the secondary activity in RTL, which should split with the main
+ * activity based on the split pair rule.
+ */
+ fun launchSecondaryActivityRTL(wmHelper: WindowManagerStateHelper) {
+ val launchButton =
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_secondary_activity_rtl_button")),
+ FIND_TIMEOUT
+ )
+ require(launchButton != null) {
+ "Can't find launch secondary activity rtl button on screen."
+ }
+ launchButton.click()
+ wmHelper
+ .StateSyncBuilder()
+ .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .waitForAndVerify()
}
/**
@@ -119,6 +138,25 @@
.waitForAndVerify()
}
+ /**
+ * Clicks the button to launch the placeholder primary activity in RTL, which should launch the
+ * placeholder secondary activity based on the placeholder rule.
+ */
+ fun launchPlaceholderSplitRTL(wmHelper: WindowManagerStateHelper) {
+ val launchButton =
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_placeholder_split_rtl_button")),
+ FIND_TIMEOUT
+ )
+ require(launchButton != null) { "Can't find launch placeholder split button on screen." }
+ launchButton.click()
+ wmHelper
+ .StateSyncBuilder()
+ .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .waitForAndVerify()
+ }
+
companion object {
private const val TAG = "ActivityEmbeddingAppHelper"
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 9227e07..5c8cbe4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -19,7 +19,7 @@
package com.android.server.wm.flicker.helpers
import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.IFlickerTestData
+import android.tools.device.flicker.legacy.FlickerTestData
import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
/**
@@ -27,7 +27,7 @@
*
* @param rotation New device rotation
*/
-fun IFlickerTestData.setRotation(rotation: Rotation) =
+fun FlickerTestData.setRotation(rotation: Rotation) =
ChangeDisplayOrientationRule.setRotation(
rotation,
instrumentation,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index 34581bb..d83b6d3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
-import android.tools.common.datatypes.Region
import android.tools.common.datatypes.Rect
+import android.tools.common.datatypes.Region
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.helpers.FIND_TIMEOUT
@@ -81,15 +81,20 @@
displayBounds: Rect,
right: Boolean
) {
- wmHelper.StateSyncBuilder().add("letterboxAppRepositioned") {
- val letterboxAppWindow = getWindowRegion(wmHelper)
- val appRegionBounds = letterboxAppWindow.bounds
- val appWidth = appRegionBounds.width
- return@add if (right) appRegionBounds.left == displayBounds.right - appWidth &&
- appRegionBounds.right == displayBounds.right
- else appRegionBounds.left == displayBounds.left &&
- appRegionBounds.right == displayBounds.left + appWidth
- }.waitForAndVerify()
+ wmHelper
+ .StateSyncBuilder()
+ .add("letterboxAppRepositioned") {
+ val letterboxAppWindow = getWindowRegion(wmHelper)
+ val appRegionBounds = letterboxAppWindow.bounds
+ val appWidth = appRegionBounds.width
+ return@add if (right)
+ appRegionBounds.left == displayBounds.right - appWidth &&
+ appRegionBounds.right == displayBounds.right
+ else
+ appRegionBounds.left == displayBounds.left &&
+ appRegionBounds.right == displayBounds.left + appWidth
+ }
+ .waitForAndVerify()
}
fun waitForAppToMoveVerticallyTo(
@@ -98,15 +103,20 @@
navBarHeight: Int,
bottom: Boolean
) {
- wmHelper.StateSyncBuilder().add("letterboxAppRepositioned") {
- val letterboxAppWindow = getWindowRegion(wmHelper)
- val appRegionBounds = letterboxAppWindow.bounds
- val appHeight = appRegionBounds.height
- return@add if (bottom) appRegionBounds.bottom == displayBounds.bottom &&
- appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight)
- else appRegionBounds.top == displayBounds.top &&
- appRegionBounds.bottom == displayBounds.top + appHeight
- }.waitForAndVerify()
+ wmHelper
+ .StateSyncBuilder()
+ .add("letterboxAppRepositioned") {
+ val letterboxAppWindow = getWindowRegion(wmHelper)
+ val appRegionBounds = letterboxAppWindow.bounds
+ val appHeight = appRegionBounds.height
+ return@add if (bottom)
+ appRegionBounds.bottom == displayBounds.bottom &&
+ appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight)
+ else
+ appRegionBounds.top == displayBounds.top &&
+ appRegionBounds.bottom == displayBounds.top + appHeight
+ }
+ .waitForAndVerify()
}
private fun getWindowRegion(wmHelper: WindowManagerStateHelper): Region {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 7e0632d..98446c1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -22,8 +22,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper
@@ -37,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeOnDismissPopupDialogTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeOnDismissPopupDialogTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val imeTestApp = ImeEditorPopupDialogAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -101,10 +101,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt
index c355e27..d87a1da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,15 +28,14 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeOnDismissPopupDialogTestCfArm(flicker: FlickerTest) :
+class CloseImeOnDismissPopupDialogTestCfArm(flicker: LegacyFlickerTest) :
CloseImeOnDismissPopupDialogTest(flicker) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 122a6cb..b995d3df 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -16,15 +16,14 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -42,7 +41,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeOnGoHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -104,7 +103,6 @@
@Presubmit
@Test
@PlatinumTest(focusArea = "ime")
- @IwTest(focusArea = "ime")
override fun cujCompleted() {
super.cujCompleted()
imeLayerBecomesInvisible()
@@ -117,10 +115,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt
index 0fe52df..3b5bfa9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,4 +26,4 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeOnGoHomeTestCfArm(flicker: FlickerTest) : CloseImeOnGoHomeTest(flicker)
+class CloseImeOnGoHomeTestCfArm(flicker: LegacyFlickerTest) : CloseImeOnGoHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index cbe03dc..765bb4c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
@@ -49,7 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartOnGoHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeShownOnAppStartOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
@@ -94,11 +94,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// b/190352379 (IME doesn't show on app launch in 90 degrees)
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt
index 5aacb30..58411cc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartOnGoHomeTestCfArm(flicker: FlickerTest) :
+open class CloseImeShownOnAppStartOnGoHomeTestCfArm(flicker: LegacyFlickerTest) :
CloseImeShownOnAppStartOnGoHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index 82c390b..c87217b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
@@ -49,7 +49,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartToAppOnPressBackTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeShownOnAppStartToAppOnPressBackTest(flicker: LegacyFlickerTest) :
+ BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
@@ -88,11 +89,10 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
// b/190352379 (IME doesn't show on app launch in 90 degrees)
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt
index eb81aed..41b06c0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeShownOnAppStartToAppOnPressBackTestCfArm(flicker: FlickerTest) :
+class CloseImeShownOnAppStartToAppOnPressBackTestCfArm(flicker: LegacyFlickerTest) :
CloseImeShownOnAppStartToAppOnPressBackTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 5aa4382..c74870b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -16,14 +16,13 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -43,7 +42,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToAppOnPressBackTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -105,7 +104,6 @@
@Presubmit
@Test
@PlatinumTest(focusArea = "ime")
- @IwTest(focusArea = "ime")
override fun cujCompleted() {
super.cujCompleted()
imeLayerBecomesInvisible()
@@ -117,8 +115,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt
index db1440b..104af22 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeToAppOnPressBackTestCfArm(flicker: FlickerTest) :
+class CloseImeToAppOnPressBackTestCfArm(flicker: LegacyFlickerTest) :
CloseImeToAppOnPressBackTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index 6731089..21fd590 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -17,14 +17,13 @@
package com.android.server.wm.flicker.ime
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -45,7 +44,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToHomeOnFinishActivityTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class CloseImeToHomeOnFinishActivityTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val simpleApp = SimpleAppHelper(instrumentation)
private val testApp = ImeAppHelper(instrumentation)
@@ -73,7 +72,6 @@
@Presubmit
@Test
@PlatinumTest(focusArea = "ime")
- @IwTest(focusArea = "ime")
override fun cujCompleted() {
runAndIgnoreAssumptionViolation { entireScreenCovered() }
runAndIgnoreAssumptionViolation { statusBarLayerIsVisibleAtStartAndEnd() }
@@ -92,10 +90,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt
index 405ab6b..0e18385 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToHomeOnFinishActivityTestCfArm(flicker: FlickerTest) :
+open class CloseImeToHomeOnFinishActivityTestCfArm(flicker: LegacyFlickerTest) :
CloseImeToHomeOnFinishActivityTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 8e33719..777231e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -19,21 +19,21 @@
package com.android.server.wm.flicker.ime
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
-fun FlickerTest.imeLayerBecomesVisible() {
+fun LegacyFlickerTest.imeLayerBecomesVisible() {
assertLayers {
this.isInvisible(ComponentNameMatcher.IME).then().isVisible(ComponentNameMatcher.IME)
}
}
-fun FlickerTest.imeLayerBecomesInvisible() {
+fun LegacyFlickerTest.imeLayerBecomesInvisible() {
assertLayers {
this.isVisible(ComponentNameMatcher.IME).then().isInvisible(ComponentNameMatcher.IME)
}
}
-fun FlickerTest.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
+fun LegacyFlickerTest.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
assertWm {
this.isNonAppWindowVisible(ComponentNameMatcher.IME)
@@ -47,7 +47,7 @@
}
}
-fun FlickerTest.imeWindowBecomesVisible() {
+fun LegacyFlickerTest.imeWindowBecomesVisible() {
assertWm {
this.isNonAppWindowInvisible(ComponentNameMatcher.IME)
.then()
@@ -55,7 +55,7 @@
}
}
-fun FlickerTest.imeWindowBecomesInvisible() {
+fun LegacyFlickerTest.imeWindowBecomesInvisible() {
assertWm {
this.isNonAppWindowVisible(ComponentNameMatcher.IME)
.then()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 19bbf0c..976ac82 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -22,8 +22,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -42,7 +42,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowToFixedPortraitAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+class OpenImeWindowToFixedPortraitAppTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
@@ -99,19 +99,18 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations =
listOf(
Rotation.ROTATION_90,
),
supportedNavigationModes = listOf(NavBar.MODE_3BUTTON, NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt
index 03f21f9..db80001 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppCfArmTest(flicker: FlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppCfArmTest(flicker: LegacyFlickerTest) :
ShowImeOnAppStartWhenLaunchingAppTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index 496165a..44bd8c8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -16,17 +16,17 @@
package com.android.server.wm.flicker.ime
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
-import android.platform.test.annotations.Postsubmit
import android.tools.common.Timestamp
-import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.flicker.subject.exceptions.ExceptionMessageBuilder
import android.tools.common.flicker.subject.exceptions.InvalidPropertyException
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
@@ -47,7 +47,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: FlickerTest) :
+open class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val imeTestApp =
ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
@@ -93,33 +93,35 @@
layerTraceEntries.zipWithNext { prev, next ->
val prevSnapshotLayerVisible =
- ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers)
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers)
val nextSnapshotLayerVisible =
- ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)
- if (imeSnapshotRemovedTimestamp == null &&
- (prevSnapshotLayerVisible && !nextSnapshotLayerVisible)) {
+ if (
+ imeSnapshotRemovedTimestamp == null &&
+ (prevSnapshotLayerVisible && !nextSnapshotLayerVisible)
+ ) {
imeSnapshotRemovedTimestamp = next.timestamp
}
}
// if so, make an assertion
imeSnapshotRemovedTimestamp?.let { timestamp ->
- val stateAfterSnapshot = layerTrace?.getEntryAt(timestamp)
- ?: error("State not found for $timestamp")
+ val stateAfterSnapshot =
+ layerTrace?.getEntryAt(timestamp) ?: error("State not found for $timestamp")
- val imeLayers = ComponentNameMatcher.IME
- .filterLayers(stateAfterSnapshot.visibleLayers.toList())
+ val imeLayers =
+ ComponentNameMatcher.IME.filterLayers(stateAfterSnapshot.visibleLayers.toList())
require(imeLayers.isNotEmpty()) { "IME layer not found" }
if (imeLayers.any { it.color.a != 1.0f }) {
- val errorMsgBuilder = ExceptionMessageBuilder()
+ val errorMsgBuilder =
+ ExceptionMessageBuilder()
.setTimestamp(timestamp)
.forInvalidProperty("IME layer alpha")
.setExpected("is 1.0")
.setActual("not 1.0")
- .addExtraDescription("Filter",
- ComponentNameMatcher.IME.toLayerIdentifier())
+ .addExtraDescription("Filter", ComponentNameMatcher.IME.toLayerIdentifier())
throw InvalidPropertyException(errorMsgBuilder)
}
}
@@ -129,15 +131,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_90)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt
index 3aca2a0..6d9ea22 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm(flicker: FlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm(flicker: LegacyFlickerTest) :
ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index f64ad53..ae05e37 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.reopenAppFromOverview
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -41,7 +41,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: FlickerTest) :
+open class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
@@ -140,10 +140,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt
index e1aa418..92b3968 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,16 +28,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm(flicker: FlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm(flicker: LegacyFlickerTest) :
ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 11bc7b9..c991651 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -22,8 +22,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
@@ -44,7 +44,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
-open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker: FlickerTest) :
+open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val imeTestApp =
@@ -121,12 +121,11 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
private const val TAG_IME_VISIBLE = "imeVisible"
private const val TAG_IME_INVISIBLE = "imeInVisible"
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt
index 0f57467..09bfacc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt
@@ -18,7 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,5 +28,5 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
-open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm(flicker: FlickerTest) :
+open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm(flicker: LegacyFlickerTest) :
ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 46967db..9763521 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
@@ -79,7 +79,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ShowImeOnAppStartWhenLaunchingAppTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
private val initializeApp = ImeStateInitializeHelper(instrumentation)
@@ -123,15 +123,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index c70e3cb..7bd5825 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -16,14 +16,13 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -38,7 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhenFocusingOnInputFieldTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ShowImeWhenFocusingOnInputFieldTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -54,7 +53,6 @@
@Presubmit
@Test
@PlatinumTest(focusArea = "ime")
- @IwTest(focusArea = "ime")
override fun cujCompleted() {
super.cujCompleted()
imeWindowBecomesVisible()
@@ -81,10 +79,9 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt
index f5b2294..f8c8149 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhenFocusingOnInputFieldTestCfArm(flicker: FlickerTest) :
+class ShowImeWhenFocusingOnInputFieldTestCfArm(flicker: LegacyFlickerTest) :
ShowImeWhenFocusingOnInputFieldTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 277b9155..0b168ba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.view.WindowInsets.Type.ime
import android.view.WindowInsets.Type.navigationBars
import android.view.WindowInsets.Type.statusBars
@@ -45,7 +45,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhileDismissingThemedPopupDialogTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ShowImeWhileDismissingThemedPopupDialogTest(flicker: LegacyFlickerTest) :
+ BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
@@ -84,15 +85,14 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt
index 8891d26..ad41b81 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,21 +28,20 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhileDismissingThemedPopupDialogTestCfArm(flicker: FlickerTest) :
+class ShowImeWhileDismissingThemedPopupDialogTestCfArm(flicker: LegacyFlickerTest) :
ShowImeWhileDismissingThemedPopupDialogTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index 9275d6a..7722c93 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -45,7 +45,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhileEnteringOverviewTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val imeTestApp =
ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
@@ -205,13 +205,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt
index fc39713..90fbbf9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -26,5 +26,5 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhileEnteringOverviewTestCfArm(flicker: FlickerTest) :
+class ShowImeWhileEnteringOverviewTestCfArm(flicker: LegacyFlickerTest) :
ShowImeWhileEnteringOverviewTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index a87fae8..3461907 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -20,8 +20,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -57,7 +57,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ActivityTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class ActivityTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -119,13 +119,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
index 85344a1..6bbf40e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.launch
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,18 +27,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ActivityTransitionTestCfArm(flicker: FlickerTest) : ActivityTransitionTest(flicker) {
+class ActivityTransitionTestCfArm(flicker: LegacyFlickerTest) : ActivityTransitionTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 5752065..ae1f78a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -20,8 +20,8 @@
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
@@ -55,7 +55,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIconColdTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -207,13 +208,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
index d453c1a..2563bfb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
@@ -19,8 +19,8 @@
import android.platform.test.annotations.FlakyTest
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -32,7 +32,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIconColdTestCfArm(flicker: FlickerTest) : OpenAppFromIconColdTest(flicker) {
+class OpenAppFromIconColdTestCfArm(flicker: LegacyFlickerTest) : OpenAppFromIconColdTest(flicker) {
@Test
@FlakyTest
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
@@ -43,13 +43,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index e747315..c95c548 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -19,8 +19,8 @@
import android.tools.device.apphelpers.CameraAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -38,7 +38,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentColdAfterCameraTest(flicker: FlickerTest) :
+open class OpenAppFromIntentColdAfterCameraTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
private val cameraApp = CameraAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -62,13 +62,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
index 177ad7d..117cff2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.launch
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,19 +27,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentColdAfterCameraTestCfArm(flicker: FlickerTest) :
+class OpenAppFromIntentColdAfterCameraTestCfArm(flicker: LegacyFlickerTest) :
OpenAppFromIntentColdAfterCameraTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index f45f728..33302fa 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -21,8 +21,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
@@ -58,7 +58,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentColdTest(flicker: FlickerTest) :
+open class OpenAppFromIntentColdTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -83,13 +83,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
index 0d695f3..45fb453 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
@@ -19,8 +19,8 @@
import android.platform.test.annotations.FlakyTest
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -31,7 +31,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentColdTestCfArm(flicker: FlickerTest) : OpenAppFromIntentColdTest(flicker) {
+class OpenAppFromIntentColdTestCfArm(flicker: LegacyFlickerTest) :
+ OpenAppFromIntentColdTest(flicker) {
@FlakyTest(bugId = 273696733)
@Test
override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
@@ -40,13 +41,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index a42bff5..12ee7d0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -21,8 +21,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -58,7 +58,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentWarmTest(flicker: FlickerTest) :
+open class OpenAppFromIntentWarmTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -94,13 +94,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
index b6ffcb3..1371fd7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,18 +29,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentWarmTestCfArm(flicker: FlickerTest) : OpenAppFromIntentWarmTest(flicker) {
+class OpenAppFromIntentWarmTestCfArm(flicker: LegacyFlickerTest) :
+ OpenAppFromIntentWarmTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
index 3d5a8e3..62fb570 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
@@ -18,12 +18,13 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.replacesLayer
import org.junit.Test
/** Base class for app launch tests */
-abstract class OpenAppFromLauncherTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
+abstract class OpenAppFromLauncherTransition(flicker: LegacyFlickerTest) :
+ OpenAppTransition(flicker) {
/** Checks that the focus changes from the [ComponentNameMatcher.LAUNCHER] to [testApp] */
@Presubmit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
index fd42726..74563a2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationColdTest.kt
@@ -21,8 +21,8 @@
import android.provider.Settings
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.ClassRule
import org.junit.FixMethodOrder
@@ -44,7 +44,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-open class OpenAppFromLockscreenNotificationColdTest(flicker: FlickerTest) :
+open class OpenAppFromLockscreenNotificationColdTest(flicker: LegacyFlickerTest) :
OpenAppFromNotificationColdTest(flicker) {
override val openingNotificationsFromLockScreen = true
@@ -111,14 +111,12 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
/**
* Ensures that posted notifications will be visible on the lockscreen and not suppressed
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
index fd051d5..2f92206 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -23,8 +23,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
import org.junit.ClassRule
@@ -46,7 +46,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromLockscreenNotificationWarmTest(flicker: FlickerTest) :
+class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) :
OpenAppFromNotificationWarmTest(flicker) {
override val openingNotificationsFromLockScreen = true
@@ -143,14 +143,12 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
/**
* Ensures that posted notifications will be visible on the lockscreen and not suppressed
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index 37afa8d..0ae514a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -22,8 +22,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
@@ -46,7 +46,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: FlickerTest) :
+class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: LegacyFlickerTest) :
OpenAppFromLockscreenNotificationColdTest(flicker) {
private val showWhenLockedApp = ShowWhenLockedAppHelper(instrumentation)
@@ -126,13 +126,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
index 30c3ec2..687bc19 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
@@ -20,7 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.navBarLayerPositionAtEnd
import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
import org.junit.Assume
@@ -28,7 +28,8 @@
import org.junit.Test
/** Base class for app launch tests from lock screen */
-abstract class OpenAppFromLockscreenTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
+abstract class OpenAppFromLockscreenTransition(flicker: LegacyFlickerTest) :
+ OpenAppTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 924d03f..46eb257 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -23,8 +23,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import org.junit.Assume
@@ -63,7 +63,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromLockscreenViaIntentTest(flicker: FlickerTest) :
+open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) :
OpenAppFromLockscreenTransition(flicker) {
override val testApp = NonResizeableAppHelper(instrumentation)
@@ -210,16 +210,15 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
index d873ec5..6f99ad2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
import org.junit.FixMethodOrder
@@ -42,7 +42,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-open class OpenAppFromNotificationColdTest(flicker: FlickerTest) :
+open class OpenAppFromNotificationColdTest(flicker: LegacyFlickerTest) :
OpenAppFromNotificationWarmTest(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -99,13 +99,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
index fb2a48c..4ec0209 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdTestCfArm.kt
@@ -18,8 +18,8 @@
import android.platform.test.annotations.Postsubmit
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,19 +29,17 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Postsubmit
-class OpenAppFromNotificationColdTestCfArm(flicker: FlickerTest) :
+class OpenAppFromNotificationColdTestCfArm(flicker: LegacyFlickerTest) :
OpenAppFromNotificationColdTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
index 99668ec..3b6c7bd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTest.kt
@@ -21,8 +21,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import android.view.WindowInsets
import android.view.WindowManager
@@ -53,7 +53,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromNotificationWarmTest(flicker: FlickerTest) : OpenAppTransition(flicker) {
+open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) :
+ OpenAppTransition(flicker) {
override val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
open val openingNotificationsFromLockScreen = false
@@ -193,13 +194,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
index 2a2597e..b5db3b0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarmTestCfArm.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.launch
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,19 +27,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromNotificationWarmTestCfArm(flicker: FlickerTest) :
+class OpenAppFromNotificationWarmTestCfArm(flicker: LegacyFlickerTest) :
OpenAppFromNotificationWarmTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
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
index 8e1b059..1497e50 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -22,8 +22,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -60,7 +60,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromOverviewTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromOverviewTest(flicker: LegacyFlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -106,13 +107,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt
index ff24190..9b6c136 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.device.flicker.annotation.FlickerServiceCompatible
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -30,18 +30,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromOverviewTestCfArm(flicker: FlickerTest) : OpenAppFromOverviewTest(flicker) {
+open class OpenAppFromOverviewTestCfArm(flicker: LegacyFlickerTest) :
+ OpenAppFromOverviewTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 87a14c6..bb11be5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -20,7 +20,7 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -28,7 +28,7 @@
import org.junit.Test
/** Base class for app launch tests */
-abstract class OpenAppTransition(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class OpenAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 6ee8ae6..4a1bd7e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -22,8 +22,8 @@
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import android.view.KeyEvent
import androidx.test.filters.RequiresDevice
@@ -60,7 +60,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenCameraFromHomeOnDoubleClickPowerButtonTest(flicker: FlickerTest) :
+class OpenCameraFromHomeOnDoubleClickPowerButtonTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
private val cameraApp = CameraAppHelper(instrumentation)
override val testApp: StandardAppHelper
@@ -155,13 +155,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index b48611e..98e3646 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -25,8 +25,8 @@
import android.tools.device.flicker.junit.FlickerBuilderProvider
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import androidx.test.filters.RequiresDevice
@@ -54,7 +54,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OverrideTaskTransitionTest(val flicker: FlickerTest) {
+class OverrideTaskTransitionTest(val flicker: LegacyFlickerTest) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
@@ -121,8 +121,6 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index d0fd732..39c8ca0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -28,8 +28,8 @@
import android.tools.common.traces.component.IComponentMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.RequiresDevice
@@ -58,7 +58,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class TaskTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
+class TaskTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val launchNewTaskApp = NewTasksAppHelper(instrumentation)
private val simpleApp = SimpleAppHelper(instrumentation)
private val wallpaper by lazy { getWallpaperPackage(instrumentation) }
@@ -214,8 +214,6 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index a8b80ad..7883910 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -23,8 +23,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
@@ -52,7 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsBackTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class QuickSwitchBetweenTwoAppsBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
@@ -243,10 +243,9 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
index f970a79..f68cd5c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,15 +28,14 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchBetweenTwoAppsBackTestCfArm(flicker: FlickerTest) :
+class QuickSwitchBetweenTwoAppsBackTestCfArm(flicker: LegacyFlickerTest) :
QuickSwitchBetweenTwoAppsBackTest(flicker) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 96cd8ff..1c4c7cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -23,8 +23,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
@@ -53,7 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsForwardTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class QuickSwitchBetweenTwoAppsForwardTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
@@ -261,10 +261,9 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
index 9f48cda..3de58ac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
@@ -18,8 +18,8 @@
import android.tools.common.NavBar
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -28,15 +28,14 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchBetweenTwoAppsForwardTestCfArm(flicker: FlickerTest) :
+class QuickSwitchBetweenTwoAppsForwardTestCfArm(flicker: LegacyFlickerTest) :
QuickSwitchBetweenTwoAppsForwardTest(flicker) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 7e935f0..6417456 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -24,8 +24,8 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -52,7 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchFromLauncherTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class QuickSwitchFromLauncherTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -272,12 +272,11 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
// TODO: Test with 90 rotation
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
index af671df..84fc754 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
@@ -19,8 +19,8 @@
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -29,17 +29,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchFromLauncherTestCfArm(flicker: FlickerTest) :
+open class QuickSwitchFromLauncherTestCfArm(flicker: LegacyFlickerTest) :
QuickSwitchFromLauncherTest(flicker) {
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
// TODO: Test with 90 rotation
supportedRotations = listOf(Rotation.ROTATION_0)
)
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 7fbcfec..842ece3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,14 +16,13 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
@@ -35,7 +34,7 @@
/**
* Test opening an app and cycling through app rotations
*
- * Currently runs:
+ * Currently, runs:
* ```
* 0 -> 90 degrees
* 90 -> 0 degrees
@@ -86,7 +85,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ChangeAppRotationTest(flicker: FlickerTest) : RotationTransition(flicker) {
+open class ChangeAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
override val testApp = SimpleAppHelper(instrumentation)
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -131,7 +130,6 @@
@Test
@PlatinumTest(focusArea = "framework")
- @IwTest(focusArea = "framework")
override fun cujCompleted() {
super.cujCompleted()
focusChanges()
@@ -142,13 +140,11 @@
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
- * modes.
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.rotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt
index 0e6b20f..1ab5c5a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -27,18 +27,16 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ChangeAppRotationTestCfArm(flicker: FlickerTest) : ChangeAppRotationTest(flicker) {
+class ChangeAppRotationTestCfArm(flicker: LegacyFlickerTest) : ChangeAppRotationTest(flicker) {
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
- * modes.
+ * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
- }
+ fun getParams() = LegacyFlickerTestFactory.rotationTests()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index fe9da33..b0ca4d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -20,13 +20,13 @@
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTest
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.Test
/** Base class for app rotation tests */
-abstract class RotationTransition(flicker: FlickerTest) : BaseTest(flicker) {
+abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
protected abstract val testApp: StandardAppHelper
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 44ae14a..b6ad3cc7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,15 +16,15 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.IwTest
import android.platform.test.annotations.PlatinumTest
import android.platform.test.annotations.Presubmit
import android.tools.common.ScenarioBuilder
+import android.tools.common.ScenarioImpl
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.view.WindowManager
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
@@ -92,7 +92,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SeamlessAppRotationTest(flicker: FlickerTest) : RotationTransition(flicker) {
+open class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
override val testApp = SeamlessRotationAppHelper(instrumentation)
/** {@inheritDoc} */
@@ -215,7 +215,6 @@
@Test
@PlatinumTest(focusArea = "framework")
- @IwTest(focusArea = "framework")
override fun cujCompleted() {
appWindowFullScreen()
appWindowSeamlessRotation()
@@ -238,43 +237,50 @@
}
companion object {
- private val FlickerTest.starveUiThread
+ private val LegacyFlickerTest.starveUiThread
get() =
- getConfigValue<Boolean>(ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD)
+ scenario.getConfigValue<Boolean>(
+ ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD
+ )
?: false
@JvmStatic
protected fun createConfig(
- sourceConfig: FlickerTest,
+ sourceConfig: LegacyFlickerTest,
starveUiThread: Boolean
- ): FlickerTest {
- val originalScenario = sourceConfig.initialize("createConfig")
+ ): LegacyFlickerTest {
+ val originalScenario = sourceConfig.initialize("createConfig") as ScenarioImpl
val nameExt = if (starveUiThread) "_BUSY_UI_THREAD" else ""
val newConfig =
ScenarioBuilder()
- .fromScenario(originalScenario)
+ .forClass(originalScenario.testClass)
+ .withStartRotation(originalScenario.startRotation)
+ .withEndRotation(originalScenario.endRotation)
+ .withNavBarMode(originalScenario.navBarMode)
+ .withExtraConfigs(originalScenario.extraConfig)
+ .withDescriptionOverride(originalScenario.description)
.withExtraConfig(
ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD,
starveUiThread
)
.withDescriptionOverride("${originalScenario.description}$nameExt")
- return FlickerTest(newConfig)
+ return LegacyFlickerTest(newConfig)
}
/**
* Creates the test configurations for seamless rotation based on the default rotation tests
- * from [FlickerTestFactory.rotationTests], but adding a flag (
+ * from [LegacyFlickerTestFactory.rotationTests], but adding a flag (
* [ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD]) to indicate if the app should
* starve the UI thread of not
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests().flatMap { sourceConfig ->
- val defaultRun = createConfig(sourceConfig, starveUiThread = false)
- val busyUiRun = createConfig(sourceConfig, starveUiThread = true)
+ fun getParams() =
+ LegacyFlickerTestFactory.rotationTests().flatMap { sourceCfg ->
+ val legacyCfg = sourceCfg as LegacyFlickerTest
+ val defaultRun = createConfig(legacyCfg, starveUiThread = false)
+ val busyUiRun = createConfig(legacyCfg, starveUiThread = true)
listOf(defaultRun, busyUiRun)
}
- }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt
index b236d87..592be05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
@@ -29,22 +29,23 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SeamlessAppRotationTestCfArm(flicker: FlickerTest) : SeamlessAppRotationTest(flicker) {
+open class SeamlessAppRotationTestCfArm(flicker: LegacyFlickerTest) :
+ SeamlessAppRotationTest(flicker) {
companion object {
/**
* Creates the test configurations for seamless rotation based on the default rotation tests
- * from [FlickerTestFactory.rotationTests], but adding a flag (
+ * from [LegacyFlickerTestFactory.rotationTests], but adding a flag (
* [ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD]) to indicate if the app should
* starve the UI thread of not
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests().flatMap { sourceConfig ->
- val defaultRun = createConfig(sourceConfig, starveUiThread = false)
- val busyUiRun = createConfig(sourceConfig, starveUiThread = true)
+ fun getParams() =
+ LegacyFlickerTestFactory.rotationTests().flatMap { sourceCfg ->
+ val legacyCfg = sourceCfg as LegacyFlickerTest
+ val defaultRun = createConfig(legacyCfg, starveUiThread = false)
+ val busyUiRun = createConfig(legacyCfg, starveUiThread = true)
listOf(defaultRun, busyUiRun)
}
- }
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index dc9ff3b..6430283 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -22,7 +22,9 @@
<application android:allowBackup="false"
android:supportsRtl="true">
<uses-library android:name="androidx.window.extensions" android:required="false"/>
-
+ <property
+ android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
+ android:value="true" />
<activity android:name=".SimpleActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
android:theme="@style/CutoutShortEdges"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index f5241ca..b9d789b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -25,24 +25,39 @@
android:id="@+id/launch_secondary_activity_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_centerHorizontal="true"
android:onClick="launchSecondaryActivity"
+ android:tag="LEFT_TO_RIGHT"
android:text="Launch Secondary Activity" />
<Button
+ android:id="@+id/launch_secondary_activity_rtl_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchSecondaryActivity"
+ android:tag="RIGHT_TO_LEFT"
+ android:text="Launch Secondary Activity in RTL" />
+
+ <Button
android:id="@+id/launch_placeholder_split_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_centerHorizontal="true"
android:onClick="launchPlaceholderSplit"
+ android:tag="LEFT_TO_RIGHT"
android:text="Launch Placeholder Split" />
<Button
android:id="@+id/launch_always_expand_activity_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_centerHorizontal="true"
android:onClick="launchAlwaysExpandActivity"
android:text="Launch Always Expand Activity" />
+ <Button
+ android:id="@+id/launch_placeholder_split_rtl_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchPlaceholderSplit"
+ android:tag="RIGHT_TO_LEFT"
+ android:text="Launch Placeholder Split in RTL" />
+
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
index 6120254..817c79c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -16,22 +16,25 @@
package com.android.server.wm.flicker.testapp;
+
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.util.ArraySet;
-import android.util.Log;
import android.view.View;
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
+import androidx.annotation.NonNull;
import androidx.window.embedding.ActivityFilter;
import androidx.window.embedding.ActivityRule;
+import androidx.window.embedding.EmbeddingAspectRatio;
import androidx.window.embedding.RuleController;
-import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
-import androidx.window.extensions.embedding.EmbeddingRule;
-import androidx.window.extensions.embedding.SplitPairRule;
-import androidx.window.extensions.embedding.SplitPlaceholderRule;
-
-import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
+import androidx.window.embedding.SplitAttributes;
+import androidx.window.embedding.SplitAttributes.LayoutDirection;
+import androidx.window.embedding.SplitController;
+import androidx.window.embedding.SplitPairFilter;
+import androidx.window.embedding.SplitPairRule;
+import androidx.window.embedding.SplitPlaceholderRule;
+import androidx.window.embedding.SplitRule;
import java.util.HashSet;
import java.util.Set;
@@ -40,16 +43,27 @@
public class ActivityEmbeddingMainActivity extends Activity {
private static final String TAG = "ActivityEmbeddingMainActivity";
private static final float DEFAULT_SPLIT_RATIO = 0.5f;
+ private RuleController mRuleController;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_embedding_main_layout);
+ final SplitController.SplitSupportStatus status = SplitController.getInstance(
+ this).getSplitSupportStatus();
+ if (status != SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
+ throw new RuntimeException(
+ "Unable to initiate SplitController in ActivityEmbeddingMainActivity, "
+ + "splitSupportStatus = " + status);
+ }
+ mRuleController = RuleController.getInstance(this);
}
/** R.id.launch_secondary_activity_button onClick */
public void launchSecondaryActivity(View view) {
- initializeSplitRules(createSplitPairRules());
+ final String layoutDirection = view.getTag().toString();
+ mRuleController.clearRules();
+ mRuleController.addRule(createSplitPairRules(layoutDirection));
startActivity(new Intent().setComponent(
ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT));
}
@@ -73,51 +87,67 @@
/** R.id.launch_placeholder_split_button onClick */
public void launchPlaceholderSplit(View view) {
- initializeSplitRules(createSplitPlaceholderRules());
+ final String layoutDirection = view.getTag().toString();
+ mRuleController.clearRules();
+ mRuleController.addRule(createSplitPlaceholderRules(layoutDirection));
startActivity(new Intent().setComponent(
ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT));
}
- private void initializeSplitRules(Set<EmbeddingRule> rules) {
- ActivityEmbeddingComponent embeddingComponent =
- ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
- if (embeddingComponent == null) {
- // Embedding not supported
- Log.d(TAG, "ActivityEmbedding is not supported on this device");
- finish();
- return;
+ private static SplitPairRule createSplitPairRules(@NonNull String layoutDirection) {
+ final Set<SplitPairFilter> pairFilters = new HashSet<>();
+ final SplitPairFilter activitiesPair = new SplitPairFilter(
+ ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT,
+ ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT,
+ null /* secondaryActivityIntentAction */);
+ pairFilters.add(activitiesPair);
+ final SplitAttributes splitAttributes = new SplitAttributes.Builder()
+ .setSplitType(SplitAttributes.SplitType.SPLIT_TYPE_EQUAL)
+ .setLayoutDirection(parseLayoutDirection(layoutDirection))
+ .build();
+ // Setting thresholds to ALWAYS_ALLOW values to make it easy for running on all devices.
+ final SplitPairRule rule = new SplitPairRule.Builder(pairFilters)
+ .setDefaultSplitAttributes(splitAttributes)
+ .setMinWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMinHeightDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMinSmallestWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
+ .setMaxAspectRatioInLandscape(EmbeddingAspectRatio.ALWAYS_ALLOW)
+ .build();
+ return rule;
+ }
+
+ private static SplitPlaceholderRule createSplitPlaceholderRules(
+ @NonNull String layoutDirection) {
+ final Set<ActivityFilter> activityFilters = new HashSet<>();
+ activityFilters.add(new ActivityFilter(
+ ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT,
+ null /* intentAction */));
+ final Intent intent = new Intent();
+ intent.setComponent(
+ ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT);
+ final SplitAttributes splitAttributes = new SplitAttributes.Builder()
+ .setSplitType(SplitAttributes.SplitType.SPLIT_TYPE_EQUAL)
+ .setLayoutDirection(parseLayoutDirection(layoutDirection))
+ .build();
+ final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(activityFilters, intent)
+ .setDefaultSplitAttributes(splitAttributes)
+ .setMinWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMinHeightDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMinSmallestWidthDp(SplitRule.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW)
+ .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
+ .setMaxAspectRatioInLandscape(EmbeddingAspectRatio.ALWAYS_ALLOW)
+ .build();
+ return rule;
+ }
+
+ private static LayoutDirection parseLayoutDirection(@NonNull String layoutDirectionStr) {
+ if (layoutDirectionStr.equals(LayoutDirection.LEFT_TO_RIGHT.toString())) {
+ return LayoutDirection.LEFT_TO_RIGHT;
}
- embeddingComponent.setEmbeddingRules(rules);
- }
-
- private Set<EmbeddingRule> createSplitPairRules() {
- final Set<EmbeddingRule> rules = new ArraySet<>();
- final SplitPairRule rule = new SplitPairRule.Builder(
- activitiesPair -> activitiesPair.first instanceof ActivityEmbeddingMainActivity
- && activitiesPair.second instanceof ActivityEmbeddingSecondaryActivity,
- activityIntentPair ->
- activityIntentPair.first instanceof ActivityEmbeddingMainActivity
- && activityIntentPair.second.getComponent().equals(ActivityOptions
- .ActivityEmbedding.SecondaryActivity.COMPONENT),
- windowMetrics -> true)
- .setSplitRatio(DEFAULT_SPLIT_RATIO)
- .build();
- rules.add(rule);
- return rules;
- }
-
- private Set<EmbeddingRule> createSplitPlaceholderRules() {
- final Set<EmbeddingRule> rules = new ArraySet<>();
- final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(
- new Intent().setComponent(
- ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT),
- activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
- intent -> intent.getComponent().equals(
- ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT),
- windowMetrics -> true)
- .setSplitRatio(DEFAULT_SPLIT_RATIO)
- .build();
- rules.add(rule);
- return rules;
+ if (layoutDirectionStr.equals(LayoutDirection.RIGHT_TO_LEFT.toString())) {
+ return LayoutDirection.RIGHT_TO_LEFT;
+ }
+ return LayoutDirection.LOCALE;
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 0f5c003..5210618 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -186,6 +186,8 @@
public static final String LABEL = "SplitScreenPrimaryActivity";
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".SplitScreenActivity");
+
+ public static final String EXTRA_LAUNCH_ADJACENT = "launch_adjacent";
}
public static class Secondary {
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java
index 70196ae..8a27252 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SplitScreenActivity.java
@@ -16,9 +16,14 @@
package com.android.server.wm.flicker.testapp;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary.EXTRA_LAUNCH_ADJACENT;
+
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
+import androidx.annotation.Nullable;
+
public class SplitScreenActivity extends Activity {
@Override
@@ -26,4 +31,17 @@
super.onCreate(icicle);
setContentView(R.layout.activity_splitscreen);
}
+
+ @Override
+ protected void onPostCreate(@Nullable Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ final boolean startSecondaryActivity = getIntent().hasExtra(EXTRA_LAUNCH_ADJACENT);
+ if (startSecondaryActivity) {
+ final Intent intent = new Intent(this, SplitScreenSecondaryActivity.class);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ startActivity(intent);
+ }
+ }
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 80c7a21..db3a992 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -789,6 +789,15 @@
</intent-filter>
</activity>
+ <activity android:name="BackdropBlurActivity"
+ android:label="RenderEffect/BackdropBlur"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="BlurActivity"
android:label="RenderEffect/Blur"
android:exported="true">
diff --git a/tests/HwAccelerationTest/res/drawable/robot_repeated.xml b/tests/HwAccelerationTest/res/drawable/robot_repeated.xml
new file mode 100644
index 0000000..bbb15b7
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/robot_repeated.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/robot"
+ android:tileMode="repeat" android:gravity="fill" />
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java
new file mode 100644
index 0000000..8086b29
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Outline;
+import android.graphics.RenderEffect;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ScrollView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BackdropBlurActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final ScrollView scrollView = new ScrollView(this);
+ final FrameLayout innerFrame = new FrameLayout(this);
+ final View backgroundView = new View(this);
+ backgroundView.setBackgroundResource(R.drawable.robot_repeated);
+ innerFrame.addView(backgroundView, ViewGroup.LayoutParams.MATCH_PARENT, 10000);
+ scrollView.addView(innerFrame,
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ final FrameLayout contentView = new FrameLayout(this);
+ contentView.addView(scrollView,
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ contentView.addView(new BackdropBlurView(this), 300, 300);
+ setContentView(contentView);
+ }
+
+ private static class BackdropBlurView extends View {
+ private final float mBlurRadius = 60f;
+ private final float mSaturation = 1.8f;
+
+ private float mDownOffsetX;
+ private float mDownOffsetY;
+
+ BackdropBlurView(Context c) {
+ super(c);
+
+ // init RenderEffect.
+ final RenderEffect blurEffect = RenderEffect.createBlurEffect(
+ mBlurRadius, mBlurRadius,
+ null, Shader.TileMode.MIRROR // TileMode.MIRROR is better for blur.
+ );
+
+ final ColorMatrix colorMatrix = new ColorMatrix();
+ colorMatrix.setSaturation(mSaturation);
+ final RenderEffect effect = RenderEffect.createColorFilterEffect(
+ new ColorMatrixColorFilter(colorMatrix), blurEffect
+ );
+ setBackdropRenderEffect(effect);
+
+ // clip to a round outline.
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View v, Outline outline) {
+ outline.setOval(0, 0, v.getWidth(), v.getHeight());
+ }
+ });
+ setClipToOutline(true);
+
+ animate().setInterpolator(new DecelerateInterpolator(2.0f));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawColor(0x99F0F0F0);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mDownOffsetX = event.getRawX() - getTranslationX();
+ mDownOffsetY = event.getRawY() - getTranslationY();
+ animate().scaleX(1.5f).scaleY(1.5f).start();
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ animate().scaleX(1f).scaleY(1f).start();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ setTranslationX(event.getRawX() - mDownOffsetX);
+ setTranslationY(event.getRawY() - mDownOffsetY);
+ break;
+ }
+ return true;
+ }
+ }
+}
diff --git a/tests/UiBench/Android.bp b/tests/UiBench/Android.bp
index 0d2f2ef..90e61c5 100644
--- a/tests/UiBench/Android.bp
+++ b/tests/UiBench/Android.bp
@@ -24,5 +24,6 @@
"androidx.recyclerview_recyclerview",
"androidx.leanback_leanback",
],
+ certificate: "platform",
test_suites: ["device-tests"],
}
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 4fc6ec7..47211c5 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.test.uibench">
+ <uses-permission android:name="android.permission.INJECT_EVENTS" />
<application android:allowBackup="false"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index a1953c6..f056110 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -144,10 +144,9 @@
// 2) the entries will be accessed on platforms U+, and
// 3) all entry keys can be encoded in 16 bits
bool UseCompactEntries(const ConfigDescription& config, std::vector<FlatEntry>* entries) const {
- return compact_entries_ &&
- (context_->GetMinSdkVersion() > SDK_TIRAMISU || config.sdkVersion > SDK_TIRAMISU) &&
- std::none_of(entries->cbegin(), entries->cend(),
- [](const auto& e) { return e.entry_key >= std::numeric_limits<uint16_t>::max(); });
+ return compact_entries_ && context_->GetMinSdkVersion() > SDK_TIRAMISU &&
+ std::none_of(entries->cbegin(), entries->cend(),
+ [](const auto& e) { return e.entry_key >= std::numeric_limits<uint16_t>::max(); });
}
std::unique_ptr<ResEntryWriter> GetResEntryWriter(bool dedup, bool compact, BigBuffer* buffer) {