Merge "Allow NotificationListenerService to be unbound by default"
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 4daf12a..4bddbd6 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -244,7 +244,7 @@
label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging",
color=black,shape=diamond
]
- LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=blue,shape=oval]
+ LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=red,shape=box]
LIGHT_STATE_WAITING_FOR_NETWORK [
label="LIGHT_STATE_WAITING_FOR_NETWORK\n"
+ "Coming out of LIGHT_STATE_IDLE, waiting for network",
@@ -490,9 +490,9 @@
@GuardedBy("this")
private long mNextLightIdleDelay;
@GuardedBy("this")
- private long mNextLightAlarmTime;
+ private long mNextLightIdleDelayFlex;
@GuardedBy("this")
- private long mNextLightMaintenanceAlarmTime;
+ private long mNextLightAlarmTime;
@GuardedBy("this")
private long mNextSensingTimeoutAlarmTime;
@@ -689,15 +689,6 @@
}
};
- private final AlarmManager.OnAlarmListener mLightMaintenanceAlarmListener = () -> {
- if (DEBUG) {
- Slog.d(TAG, "Light maintenance alarm fired");
- }
- synchronized (DeviceIdleController.this) {
- stepLightIdleStateLocked("s:alarm");
- }
- };
-
/** AlarmListener to start monitoring motion if there are registered stationary listeners. */
private final AlarmManager.OnAlarmListener mMotionRegistrationAlarmListener = () -> {
synchronized (DeviceIdleController.this) {
@@ -962,6 +953,9 @@
private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
"light_after_inactive_to";
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
+ private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
+ "light_idle_to_initial_flex";
+ private static final String KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX = "light_max_idle_to_flex";
private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
@@ -1010,6 +1004,10 @@
!COMPRESS_TIME ? 4 * 60 * 1000L : 30 * 1000L;
private long mDefaultLightIdleTimeout =
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
+ private long mDefaultLightIdleTimeoutInitialFlex =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
+ private long mDefaultLightIdleTimeoutMaxFlex =
+ !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
private float mDefaultLightIdleFactor = 2f;
private long mDefaultLightMaxIdleTimeout =
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
@@ -1084,6 +1082,22 @@
public long LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
/**
+ * This is the initial alarm window size that we will tolerate for light idle maintenance
+ * timing.
+ *
+ * @see #KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX
+ * @see #mNextLightIdleDelayFlex
+ */
+ public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = mDefaultLightIdleTimeoutInitialFlex;
+
+ /**
+ * This is the maximum value that {@link #mNextLightIdleDelayFlex} should take.
+ *
+ * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX
+ */
+ public long LIGHT_IDLE_TIMEOUT_MAX_FLEX = mDefaultLightIdleTimeoutMaxFlex;
+
+ /**
* Scaling factor to apply to the light idle mode time each time we complete a cycle.
*
* @see #KEY_LIGHT_IDLE_FACTOR
@@ -1321,6 +1335,14 @@
mDefaultLightIdleTimeout = getTimeout(
res.getInteger(com.android.internal.R.integer.device_idle_light_idle_to_ms),
mDefaultLightIdleTimeout);
+ mDefaultLightIdleTimeoutInitialFlex = getTimeout(
+ res.getInteger(
+ com.android.internal.R.integer.device_idle_light_idle_to_init_flex_ms),
+ mDefaultLightIdleTimeoutInitialFlex);
+ mDefaultLightIdleTimeoutMaxFlex = getTimeout(
+ res.getInteger(
+ com.android.internal.R.integer.device_idle_light_idle_to_max_flex_ms),
+ mDefaultLightIdleTimeoutMaxFlex);
mDefaultLightIdleFactor = res.getFloat(
com.android.internal.R.integer.device_idle_light_idle_factor);
mDefaultLightMaxIdleTimeout = getTimeout(
@@ -1400,6 +1422,8 @@
FLEX_TIME_SHORT = mDefaultFlexTimeShort;
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
+ LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = mDefaultLightIdleTimeoutInitialFlex;
+ LIGHT_IDLE_TIMEOUT_MAX_FLEX = mDefaultLightIdleTimeoutMaxFlex;
LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
@@ -1457,6 +1481,16 @@
LIGHT_IDLE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_TIMEOUT, mDefaultLightIdleTimeout);
break;
+ case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX:
+ LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong(
+ KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX,
+ mDefaultLightIdleTimeoutInitialFlex);
+ break;
+ case KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX:
+ LIGHT_IDLE_TIMEOUT_MAX_FLEX = properties.getLong(
+ KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+ mDefaultLightIdleTimeoutMaxFlex);
+ break;
case KEY_LIGHT_IDLE_FACTOR:
LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));
@@ -1613,6 +1647,14 @@
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_MAX_FLEX, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
pw.print(LIGHT_IDLE_FACTOR);
pw.println();
@@ -3209,7 +3251,7 @@
if (conn != mNetworkConnected) {
mNetworkConnected = conn;
if (conn && mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
- stepLightIdleStateLocked("network", /* forceProgression */ true);
+ stepLightIdleStateLocked("network");
}
}
}
@@ -3454,11 +3496,7 @@
moveToLightStateLocked(LIGHT_STATE_INACTIVE, "no activity");
resetLightIdleManagementLocked();
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
- mConstants.FLEX_TIME_SHORT);
- // After moving in INACTIVE, the maintenance window should start the time inactive
- // timeout and a single light idle period.
- scheduleLightMaintenanceAlarmLocked(
- mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT + mConstants.LIGHT_IDLE_TIMEOUT);
+ mConstants.FLEX_TIME_SHORT, true);
}
}
@@ -3480,8 +3518,9 @@
private void resetLightIdleManagementLocked() {
mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
mMaintenanceStartTime = 0;
+ mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
- cancelAllLightAlarmsLocked();
+ cancelLightAlarmLocked();
}
@GuardedBy("this")
@@ -3515,14 +3554,9 @@
}
@GuardedBy("this")
- private void stepLightIdleStateLocked(String reason) {
- stepLightIdleStateLocked(reason, false);
- }
-
- @GuardedBy("this")
@VisibleForTesting
@SuppressLint("WakelockTimeout")
- void stepLightIdleStateLocked(String reason, boolean forceProgression) {
+ void stepLightIdleStateLocked(String reason) {
if (mLightState == LIGHT_STATE_ACTIVE || mLightState == LIGHT_STATE_OVERRIDE) {
// If we are already in deep device idle mode, then
// there is nothing left to do for light mode.
@@ -3530,91 +3564,67 @@
}
if (DEBUG) {
- Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + lightStateToString(mLightState)
- + " force=" + forceProgression);
+ Slog.d(TAG, "stepLightIdleStateLocked: mLightState=" + lightStateToString(mLightState));
}
EventLogTags.writeDeviceIdleLightStep();
- final long nowElapsed = mInjector.getElapsedRealtime();
- final boolean crossedMaintenanceTime =
- mNextLightMaintenanceAlarmTime > 0 && nowElapsed >= mNextLightMaintenanceAlarmTime;
- final boolean crossedProgressionTime =
- mNextLightAlarmTime > 0 && nowElapsed >= mNextLightAlarmTime;
- final boolean enterMaintenance;
- if (crossedMaintenanceTime) {
- if (crossedProgressionTime) {
- enterMaintenance = (mNextLightAlarmTime <= mNextLightMaintenanceAlarmTime);
- } else {
- enterMaintenance = true;
- }
- } else if (crossedProgressionTime) {
- enterMaintenance = false;
- } else if (forceProgression) {
- // This will happen for adb commands, unit tests,
- // and when we're in WAITING_FOR_NETWORK and the network connects.
- enterMaintenance =
- mLightState == LIGHT_STATE_IDLE
- || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK;
- } else {
- Slog.wtfStack(TAG, "stepLightIdleStateLocked called in invalid state: " + mLightState);
- return;
- }
-
- if (enterMaintenance) {
- if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
- // We have been idling long enough, now it is time to do some work.
- mActiveIdleOpCount = 1;
- mActiveIdleWakeLock.acquire();
- mMaintenanceStartTime = SystemClock.elapsedRealtime();
- if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
- mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
- } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
- mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
+ switch (mLightState) {
+ case LIGHT_STATE_INACTIVE:
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ // Reset the upcoming idle delays.
+ mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+ mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
+ mMaintenanceStartTime = 0;
+ // Fall through to immediately idle.
+ case LIGHT_STATE_IDLE_MAINTENANCE:
+ if (mMaintenanceStartTime != 0) {
+ long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
+ if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ // We didn't use up all of our minimum budget; add this to the reserve.
+ mCurLightIdleBudget +=
+ (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
+ } else {
+ // We used more than our minimum budget; this comes out of the reserve.
+ mCurLightIdleBudget -=
+ (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+ }
}
+ mMaintenanceStartTime = 0;
+ scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, true);
mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
(long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
- // We're entering MAINTENANCE. It should end curLightIdleBudget time from now.
- // The next maintenance window should be curLightIdleBudget + nextLightIdleDelay
- // time from now.
- scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT);
- scheduleLightMaintenanceAlarmLocked(mCurLightIdleBudget + mNextLightIdleDelay);
- moveToLightStateLocked(LIGHT_STATE_IDLE_MAINTENANCE, reason);
- addEvent(EVENT_LIGHT_MAINTENANCE, null);
- mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
- } else {
- // We'd like to do maintenance, but currently don't have network
- // connectivity... let's try to wait until the network comes back.
- // We'll only wait for another full idle period, however, and then give up.
- scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
- cancelLightAlarmLocked();
- moveToLightStateLocked(LIGHT_STATE_WAITING_FOR_NETWORK, reason);
- }
- } else {
- if (mMaintenanceStartTime != 0) {
- // Cap duration at budget since the non-wakeup alarm to exit maintenance may
- // not fire at the exact intended time, but once the system is up, we will stop
- // more ongoing work.
- long duration = Math.min(mCurLightIdleBudget,
- SystemClock.elapsedRealtime() - mMaintenanceStartTime);
- if (duration < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
- // We didn't use up all of our minimum budget; add this to the reserve.
- mCurLightIdleBudget +=
- (mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - duration);
+ mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX,
+ (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
+ moveToLightStateLocked(LIGHT_STATE_IDLE, reason);
+ addEvent(EVENT_LIGHT_IDLE, null);
+ mGoingIdleWakeLock.acquire();
+ mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
+ break;
+ case LIGHT_STATE_IDLE:
+ case LIGHT_STATE_WAITING_FOR_NETWORK:
+ if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
+ // We have been idling long enough, now it is time to do some work.
+ mActiveIdleOpCount = 1;
+ mActiveIdleWakeLock.acquire();
+ mMaintenanceStartTime = SystemClock.elapsedRealtime();
+ if (mCurLightIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+ } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
+ mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
+ }
+ scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT, true);
+ moveToLightStateLocked(LIGHT_STATE_IDLE_MAINTENANCE, reason);
+ addEvent(EVENT_LIGHT_MAINTENANCE, null);
+ mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
} else {
- // We used more than our minimum budget; this comes out of the reserve.
- mCurLightIdleBudget -=
- (duration - mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+ // We'd like to do maintenance, but currently don't have network
+ // connectivity... let's try to wait until the network comes back.
+ // We'll only wait for another full idle period, however, and then give up.
+ scheduleLightAlarmLocked(mNextLightIdleDelay,
+ mNextLightIdleDelayFlex / 2, true);
+ moveToLightStateLocked(LIGHT_STATE_WAITING_FOR_NETWORK, reason);
}
- }
- mMaintenanceStartTime = 0;
- // We're entering IDLE. We may have used less than curLightIdleBudget for the
- // maintenance window, so reschedule the alarm starting from now.
- scheduleLightMaintenanceAlarmLocked(mNextLightIdleDelay);
- cancelLightAlarmLocked();
- moveToLightStateLocked(LIGHT_STATE_IDLE, reason);
- addEvent(EVENT_LIGHT_IDLE, null);
- mGoingIdleWakeLock.acquire();
- mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
+ break;
}
}
@@ -3749,7 +3759,7 @@
moveToStateLocked(STATE_IDLE, reason);
if (mLightState != LIGHT_STATE_OVERRIDE) {
moveToLightStateLocked(LIGHT_STATE_OVERRIDE, "deep");
- cancelAllLightAlarmsLocked();
+ cancelLightAlarmLocked();
}
addEvent(EVENT_DEEP_IDLE, null);
mGoingIdleWakeLock.acquire();
@@ -3995,7 +4005,7 @@
if (mState == STATE_IDLE_MAINTENANCE) {
stepIdleStateLocked("s:early");
} else {
- stepLightIdleStateLocked("s:early", /* forceProgression */ true);
+ stepLightIdleStateLocked("s:early");
}
}
}
@@ -4103,12 +4113,6 @@
}
@GuardedBy("this")
- private void cancelAllLightAlarmsLocked() {
- cancelLightAlarmLocked();
- cancelLightMaintenanceAlarmLocked();
- }
-
- @GuardedBy("this")
private void cancelLightAlarmLocked() {
if (mNextLightAlarmTime != 0) {
mNextLightAlarmTime = 0;
@@ -4117,14 +4121,6 @@
}
@GuardedBy("this")
- private void cancelLightMaintenanceAlarmLocked() {
- if (mNextLightMaintenanceAlarmTime != 0) {
- mNextLightMaintenanceAlarmTime = 0;
- mAlarmManager.cancel(mLightMaintenanceAlarmListener);
- }
- }
-
- @GuardedBy("this")
void cancelLocatingLocked() {
if (mLocating) {
LocationManager locationManager = mInjector.getLocationManager();
@@ -4188,40 +4184,26 @@
}
@GuardedBy("this")
- @VisibleForTesting
- void scheduleLightAlarmLocked(long delay, long flex) {
+ void scheduleLightAlarmLocked(long delay, long flex, boolean wakeup) {
if (DEBUG) {
Slog.d(TAG, "scheduleLightAlarmLocked(" + delay
+ (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "")
- + ")");
+ + ", wakeup=" + wakeup + ")");
}
mNextLightAlarmTime = mInjector.getElapsedRealtime() + delay;
if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(
- AlarmManager.ELAPSED_REALTIME,
+ wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
mNextLightAlarmTime, flex,
"DeviceIdleController.light", mLightAlarmListener, mHandler);
} else {
mAlarmManager.set(
- AlarmManager.ELAPSED_REALTIME,
+ wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME,
mNextLightAlarmTime,
"DeviceIdleController.light", mLightAlarmListener, mHandler);
}
}
- @GuardedBy("this")
- @VisibleForTesting
- void scheduleLightMaintenanceAlarmLocked(long delay) {
- if (DEBUG) {
- Slog.d(TAG, "scheduleLightMaintenanceAlarmLocked(" + delay + ")");
- }
- mNextLightMaintenanceAlarmTime = mInjector.getElapsedRealtime() + delay;
- mAlarmManager.setWindow(
- AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mNextLightMaintenanceAlarmTime, mConstants.FLEX_TIME_SHORT,
- "DeviceIdleController.light", mLightMaintenanceAlarmListener, mHandler);
- }
-
@VisibleForTesting
long getNextLightAlarmTimeForTesting() {
synchronized (this) {
@@ -4229,13 +4211,6 @@
}
}
- @VisibleForTesting
- long getNextLightMaintenanceAlarmTimeForTesting() {
- synchronized (this) {
- return mNextLightMaintenanceAlarmTime;
- }
- }
-
private void scheduleMotionRegistrationAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
long nextMotionRegistrationAlarmTime =
@@ -4605,7 +4580,7 @@
pw.print("Stepped to deep: ");
pw.println(stateToString(mState));
} else if ("light".equals(arg)) {
- stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
+ stepLightIdleStateLocked("s:shell");
pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
} else {
pw.println("Unknown idle mode: " + arg);
@@ -4645,7 +4620,7 @@
becomeInactiveIfAppropriateLocked();
int curLightState = mLightState;
while (curLightState != LIGHT_STATE_IDLE) {
- stepLightIdleStateLocked("s:shell", /* forceProgression */ true);
+ stepLightIdleStateLocked("s:shell");
if (curLightState == mLightState) {
pw.print("Unable to go light idle; stopped at ");
pw.println(lightStateToString(mLightState));
@@ -5266,19 +5241,19 @@
if (mNextLightIdleDelay != 0) {
pw.print(" mNextLightIdleDelay=");
TimeUtils.formatDuration(mNextLightIdleDelay, pw);
- pw.println();
+ if (mConstants.USE_WINDOW_ALARMS) {
+ pw.print(" (flex=");
+ TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw);
+ pw.println(")");
+ } else {
+ pw.println();
+ }
}
if (mNextLightAlarmTime != 0) {
pw.print(" mNextLightAlarmTime=");
TimeUtils.formatDuration(mNextLightAlarmTime, SystemClock.elapsedRealtime(), pw);
pw.println();
}
- if (mNextLightMaintenanceAlarmTime != 0) {
- pw.print(" mNextLightMaintenanceAlarmTime=");
- TimeUtils.formatDuration(
- mNextLightMaintenanceAlarmTime, SystemClock.elapsedRealtime(), pw);
- pw.println();
- }
if (mCurLightIdleBudget != 0) {
pw.print(" mCurLightIdleBudget=");
TimeUtils.formatDuration(mCurLightIdleBudget, pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index c5510b7..6a7904c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3744,7 +3744,7 @@
// Enforce that only the app itself (or shared uid participant) can schedule a
// job that runs one of the app's services, as well as verifying that the
// named service properly requires the BIND_JOB_SERVICE permission
- private void enforceValidJobRequest(int uid, JobInfo job) {
+ private void enforceValidJobRequest(int uid, int pid, JobInfo job) {
final PackageManager pm = getContext()
.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0)
.getPackageManager();
@@ -3768,6 +3768,10 @@
throw new IllegalArgumentException(
"Tried to schedule job for non-existent component: " + service);
}
+ if (job.isPersisted() && !canPersistJobs(pid, uid)) {
+ throw new IllegalArgumentException("Requested job cannot be persisted without"
+ + " holding android.permission.RECEIVE_BOOT_COMPLETED permission");
+ }
}
private boolean canPersistJobs(int pid, int uid) {
@@ -3915,13 +3919,7 @@
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(uid);
- enforceValidJobRequest(uid, job);
- if (job.isPersisted()) {
- if (!canPersistJobs(pid, uid)) {
- throw new IllegalArgumentException("Error: requested job be persisted without"
- + " holding RECEIVE_BOOT_COMPLETED permission.");
- }
- }
+ enforceValidJobRequest(uid, pid, job);
final int result = validateJob(job, uid, -1, null, null);
if (result != JobScheduler.RESULT_SUCCESS) {
@@ -3948,9 +3946,10 @@
Slog.d(TAG, "Enqueueing job: " + job.toString() + " work: " + work);
}
final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
final int userId = UserHandle.getUserId(uid);
- enforceValidJobRequest(uid, job);
+ enforceValidJobRequest(uid, pid, job);
if (work == null) {
throw new NullPointerException("work is null");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index d048cca..ceb47ea 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -107,6 +107,8 @@
private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** Amount of time the JobScheduler will wait for a response from an app for a message. */
private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+ /** Amount of time the JobScheduler will wait for a job to provide a required notification. */
+ private static final long NOTIFICATION_TIMEOUT_MILLIS = 10_000L * Build.HW_TIMEOUT_MULTIPLIER;
private static final String[] VERB_STRINGS = {
"VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
@@ -190,6 +192,8 @@
private long mMinExecutionGuaranteeMillis;
/** The absolute maximum amount of time the job can run */
private long mMaxExecutionTimeMillis;
+ /** Whether this job is required to provide a notification and we're still waiting for it. */
+ private boolean mAwaitingNotification;
private long mEstimatedDownloadBytes;
private long mEstimatedUploadBytes;
@@ -348,6 +352,7 @@
mEstimatedDownloadBytes = job.getEstimatedNetworkDownloadBytes();
mEstimatedUploadBytes = job.getEstimatedNetworkUploadBytes();
mTransferredDownloadBytes = mTransferredUploadBytes = 0;
+ mAwaitingNotification = job.isUserVisibleJob();
final long whenDeferred = job.getWhenStandbyDeferred();
if (whenDeferred > 0) {
@@ -771,6 +776,12 @@
mNotificationCoordinator.enqueueNotification(this, callingPkgName,
callingPid, callingUid, notificationId,
notification, jobEndNotificationPolicy);
+ if (mAwaitingNotification) {
+ mAwaitingNotification = false;
+ if (mVerb == VERB_EXECUTING) {
+ scheduleOpTimeOutLocked();
+ }
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1183,6 +1194,8 @@
}
final long latestStopTimeElapsed =
mExecutionStartTimeElapsed + mMaxExecutionTimeMillis;
+ final long earliestStopTimeElapsed =
+ mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
final long nowElapsed = sElapsedRealtimeClock.millis();
if (nowElapsed >= latestStopTimeElapsed) {
// Not an error - client ran out of time.
@@ -1191,7 +1204,7 @@
mParams.setStopReason(JobParameters.STOP_REASON_TIMEOUT,
JobParameters.INTERNAL_STOP_REASON_TIMEOUT, "client timed out");
sendStopMessageLocked("timeout while executing");
- } else {
+ } else if (nowElapsed >= earliestStopTimeElapsed) {
// We've given the app the minimum execution time. See if we should stop it or
// let it continue running
final String reason = mJobConcurrencyManager.shouldStopRunningJobLocked(this);
@@ -1209,6 +1222,14 @@
+ " continue to run past min execution time");
scheduleOpTimeOutLocked();
}
+ } else if (mAwaitingNotification) {
+ onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true,
+ /* debugReason */ "timed out while stopping",
+ /* anrMessage */ "required notification not provided",
+ /* triggerAnr */ true);
+ } else {
+ Slog.e(TAG, "Unexpected op timeout while EXECUTING");
+ scheduleOpTimeOutLocked();
}
break;
default:
@@ -1402,20 +1423,24 @@
private void scheduleOpTimeOutLocked() {
removeOpTimeOutLocked();
- // TODO(260848384): enforce setNotification timeout for user-initiated jobs
final long timeoutMillis;
switch (mVerb) {
case VERB_EXECUTING:
+ long minTimeout;
final long earliestStopTimeElapsed =
mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
final long latestStopTimeElapsed =
mExecutionStartTimeElapsed + mMaxExecutionTimeMillis;
final long nowElapsed = sElapsedRealtimeClock.millis();
if (nowElapsed < earliestStopTimeElapsed) {
- timeoutMillis = earliestStopTimeElapsed - nowElapsed;
+ minTimeout = earliestStopTimeElapsed - nowElapsed;
} else {
- timeoutMillis = latestStopTimeElapsed - nowElapsed;
+ minTimeout = latestStopTimeElapsed - nowElapsed;
}
+ if (mAwaitingNotification) {
+ minTimeout = Math.min(minTimeout, NOTIFICATION_TIMEOUT_MILLIS);
+ }
+ timeoutMillis = minTimeout;
break;
case VERB_BINDING:
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 9909764..a3d566b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -286,7 +286,7 @@
/**
* Map of uids to their current app-op mode for
- * {@link AppOpsManager#OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY}.
+ * {@link AppOpsManager#OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS}.
*/
@GuardedBy("mSystemExemptionAppOpMode")
private final SparseIntArray mSystemExemptionAppOpMode = new SparseIntArray();
@@ -670,7 +670,7 @@
IAppOpsService iAppOpsService = mInjector.getAppOpsService();
try {
iAppOpsService.startWatchingMode(
- AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY,
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
/*packageName=*/ null,
new IAppOpsCallback.Stub() {
@Override
@@ -1482,7 +1482,8 @@
}
} else {
int mode = mAppOpsManager.checkOpNoThrow(
- AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY, uid, packageName);
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid,
+ packageName);
mSystemExemptionAppOpMode.put(uid, mode);
if (mode == AppOpsManager.MODE_ALLOWED) {
return STANDBY_BUCKET_EXEMPTED;
diff --git a/core/api/current.txt b/core/api/current.txt
index 765974a..8216f89 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -147,6 +147,7 @@
field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
field public static final String MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES = "android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES";
field public static final String MANAGE_DEVICE_POLICY_DEFAULT_SMS = "android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS";
+ field public static final String MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS = "android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS";
field public static final String MANAGE_DEVICE_POLICY_DISPLAY = "android.permission.MANAGE_DEVICE_POLICY_DISPLAY";
field public static final String MANAGE_DEVICE_POLICY_FACTORY_RESET = "android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET";
field public static final String MANAGE_DEVICE_POLICY_FUN = "android.permission.MANAGE_DEVICE_POLICY_FUN";
@@ -2048,16 +2049,16 @@
field public static final int system_primary_container_light;
field public static final int system_primary_dark;
field public static final int system_primary_fixed_dark;
- field public static final int system_primary_fixed_darker_dark;
- field public static final int system_primary_fixed_darker_light;
+ field public static final int system_primary_fixed_dim_dark;
+ field public static final int system_primary_fixed_dim_light;
field public static final int system_primary_fixed_light;
field public static final int system_primary_light;
field public static final int system_secondary_container_dark;
field public static final int system_secondary_container_light;
field public static final int system_secondary_dark;
field public static final int system_secondary_fixed_dark;
- field public static final int system_secondary_fixed_darker_dark;
- field public static final int system_secondary_fixed_darker_light;
+ field public static final int system_secondary_fixed_dim_dark;
+ field public static final int system_secondary_fixed_dim_light;
field public static final int system_secondary_fixed_light;
field public static final int system_secondary_light;
field public static final int system_surface_bright_dark;
@@ -2082,8 +2083,8 @@
field public static final int system_tertiary_container_light;
field public static final int system_tertiary_dark;
field public static final int system_tertiary_fixed_dark;
- field public static final int system_tertiary_fixed_darker_dark;
- field public static final int system_tertiary_fixed_darker_light;
+ field public static final int system_tertiary_fixed_dim_dark;
+ field public static final int system_tertiary_fixed_dim_light;
field public static final int system_tertiary_fixed_light;
field public static final int system_tertiary_light;
field public static final int system_text_hint_inverse_dark;
@@ -7724,27 +7725,27 @@
public class DevicePolicyManager {
method public void acknowledgeDeviceCompliant();
- method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
- method public boolean addCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional=true) public void addCrossProfileIntentFilter(@Nullable android.content.ComponentName, android.content.IntentFilter, int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional=true) public boolean addCrossProfileWidgetProvider(@Nullable android.content.ComponentName, String);
method public int addOverrideApn(@NonNull android.content.ComponentName, @NonNull android.telephony.data.ApnSetting);
- method public void addPersistentPreferredActivity(@NonNull android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public void addPersistentPreferredActivity(@Nullable android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
method public void addUserRestriction(@NonNull android.content.ComponentName, String);
method public void addUserRestrictionGlobally(@NonNull String);
method public boolean bindDeviceAdminServiceAsUser(@NonNull android.content.ComponentName, android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
method public boolean canAdminGrantSensorsPermissions();
method public boolean canUsbDataSignalingBeDisabled();
method public void clearApplicationUserData(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener);
- method public void clearCrossProfileIntentFilters(@NonNull android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional=true) public void clearCrossProfileIntentFilters(@Nullable android.content.ComponentName);
method @Deprecated public void clearDeviceOwnerApp(String);
- method public void clearPackagePersistentPreferredActivities(@NonNull android.content.ComponentName, String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public void clearPackagePersistentPreferredActivities(@Nullable android.content.ComponentName, String);
method @Deprecated public void clearProfileOwner(@NonNull android.content.ComponentName);
- method public boolean clearResetPasswordToken(android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional=true) public boolean clearResetPasswordToken(@Nullable android.content.ComponentName);
method public void clearUserRestriction(@NonNull android.content.ComponentName, String);
method public android.content.Intent createAdminSupportIntent(@NonNull String);
method @Nullable public android.os.UserHandle createAndManageUser(@NonNull android.content.ComponentName, @NonNull String, @NonNull android.content.ComponentName, @Nullable android.os.PersistableBundle, int);
method public void enableSystemApp(@NonNull android.content.ComponentName, String);
method public int enableSystemApp(@NonNull android.content.ComponentName, android.content.Intent);
- method public android.security.AttestedKeyPair generateKeyPair(@Nullable android.content.ComponentName, @NonNull String, @NonNull android.security.keystore.KeyGenParameterSpec, int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public android.security.AttestedKeyPair generateKeyPair(@Nullable android.content.ComponentName, @NonNull String, @NonNull android.security.keystore.KeyGenParameterSpec, int);
method @Nullable public String[] getAccountTypesWithManagementDisabled();
method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
@@ -7752,19 +7753,19 @@
method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
- method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@NonNull android.content.ComponentName);
+ method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@Nullable android.content.ComponentName);
method @Deprecated public boolean getAutoTimeRequired();
- method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeZoneEnabled(@NonNull android.content.ComponentName);
+ method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeZoneEnabled(@Nullable android.content.ComponentName);
method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
- method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public boolean getCameraDisabled(@Nullable android.content.ComponentName);
method @Deprecated @Nullable public String getCertInstallerPackage(@NonNull android.content.ComponentName) throws java.lang.SecurityException;
method @Nullable public android.app.admin.PackagePolicy getCredentialManagerPolicy();
method @Deprecated @Nullable public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
method @Deprecated public boolean getCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName);
method @Deprecated public boolean getCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName);
method @NonNull public java.util.Set<java.lang.String> getCrossProfilePackages(@NonNull android.content.ComponentName);
- method @NonNull public java.util.List<java.lang.String> getCrossProfileWidgetProviders(@NonNull android.content.ComponentName);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional=true) public java.util.List<java.lang.String> getCrossProfileWidgetProviders(@Nullable android.content.ComponentName);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional=true) public int getCurrentFailedPasswordAttempts();
method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
@@ -7779,8 +7780,8 @@
method @Nullable public java.util.List<java.lang.String> getKeepUninstalledPackages(@Nullable android.content.ComponentName);
method @NonNull public java.util.Map<java.lang.Integer,java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
method public int getKeyguardDisabledFeatures(@Nullable android.content.ComponentName);
- method public int getLockTaskFeatures(@NonNull android.content.ComponentName);
- method @NonNull public String[] getLockTaskPackages(@NonNull android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public int getLockTaskFeatures(@Nullable android.content.ComponentName);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public String[] getLockTaskPackages(@Nullable android.content.ComponentName);
method @Nullable public CharSequence getLongSupportMessage(@NonNull android.content.ComponentName);
method @Nullable public android.app.admin.PackagePolicy getManagedProfileCallerIdAccessPolicy();
method @Nullable public android.app.admin.PackagePolicy getManagedProfileContactsAccessPolicy();
@@ -7794,7 +7795,7 @@
method @RequiresPermission(value=android.Manifest.permission.READ_NEARBY_STREAMING_POLICY, conditional=true) public int getNearbyAppStreamingPolicy();
method @RequiresPermission(value=android.Manifest.permission.READ_NEARBY_STREAMING_POLICY, conditional=true) public int getNearbyNotificationStreamingPolicy();
method @Deprecated @ColorInt public int getOrganizationColor(@NonNull android.content.ComponentName);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY) public CharSequence getOrganizationName(@Nullable android.content.ComponentName);
+ method @Nullable @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, conditional=true) public CharSequence getOrganizationName(@Nullable android.content.ComponentName);
method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName);
method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY}, conditional=true) public int getPasswordComplexity();
@@ -7811,7 +7812,7 @@
method @Deprecated public int getPasswordMinimumUpperCase(@Nullable android.content.ComponentName);
method @Deprecated public int getPasswordQuality(@Nullable android.content.ComponentName);
method @Nullable public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(@NonNull android.content.ComponentName);
- method public int getPermissionGrantState(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, conditional=true) public int getPermissionGrantState(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public int getPermissionPolicy(android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedAccessibilityServices(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
@@ -7823,14 +7824,14 @@
method @NonNull public android.app.admin.DevicePolicyResourcesManager getResources();
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
- method public CharSequence getShortSupportMessage(@NonNull android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, conditional=true) public CharSequence getShortSupportMessage(@Nullable android.content.ComponentName);
method public CharSequence getStartUserSessionMessage(@NonNull android.content.ComponentName);
method @Deprecated public boolean getStorageEncryption(@Nullable android.content.ComponentName);
method public int getStorageEncryptionStatus();
method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
- method @NonNull public java.util.List<java.lang.String> getUserControlDisabledPackages(@NonNull android.content.ComponentName);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional=true) public java.util.List<java.lang.String> getUserControlDisabledPackages(@Nullable android.content.ComponentName);
method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
method @NonNull public android.os.Bundle getUserRestrictionsGlobally();
method @Nullable public String getWifiMacAddress(@Nullable android.content.ComponentName);
@@ -7839,13 +7840,13 @@
method public boolean grantKeyPairToWifiAuth(@NonNull String);
method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
- method public boolean hasKeyPair(@NonNull String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean hasKeyPair(@NonNull String);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI, conditional=true) public boolean hasLockdownAdminConfiguredNetworks(@Nullable android.content.ComponentName);
method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]);
method public boolean installExistingPackage(@NonNull android.content.ComponentName, String);
- method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate, @NonNull String);
- method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, boolean);
- method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate, @NonNull String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, int);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, conditional=true) public void installSystemUpdate(@Nullable android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional=true) public boolean isActivePasswordSufficient();
method public boolean isActivePasswordSufficientForDeviceRequirement();
@@ -7868,11 +7869,11 @@
method public boolean isNetworkLoggingEnabled(@Nullable android.content.ComponentName);
method public boolean isOrganizationOwnedDeviceWithManagedProfile();
method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
- method public boolean isPackageSuspended(@NonNull android.content.ComponentName, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional=true) public boolean isPackageSuspended(@Nullable android.content.ComponentName, String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isPreferentialNetworkServiceEnabled();
method public boolean isProfileOwnerApp(String);
method public boolean isProvisioningAllowed(@NonNull String);
- method public boolean isResetPasswordTokenActive(android.content.ComponentName);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional=true) public boolean isResetPasswordTokenActive(@Nullable android.content.ComponentName);
method public boolean isSafeOperation(int);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING, conditional=true) public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
method public boolean isStatusBarDisabled();
@@ -7886,40 +7887,41 @@
method public int logoutUser(@NonNull android.content.ComponentName);
method public void reboot(@NonNull android.content.ComponentName);
method public void removeActiveAdmin(@NonNull android.content.ComponentName);
- method public boolean removeCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
- method public boolean removeKeyPair(@Nullable android.content.ComponentName, @NonNull String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional=true) public boolean removeCrossProfileWidgetProvider(@Nullable android.content.ComponentName, String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean removeKeyPair(@Nullable android.content.ComponentName, @NonNull String);
method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
method public boolean requestBugreport(@NonNull android.content.ComponentName);
method @Deprecated public boolean resetPassword(String, int);
- method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional=true) public boolean resetPasswordWithToken(@Nullable android.content.ComponentName, String, byte[], int);
method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
method @Nullable @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING, conditional=true) public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@Nullable android.content.ComponentName);
method @Nullable @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING, conditional=true) public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@Nullable android.content.ComponentName);
method public boolean revokeKeyPairFromApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public boolean revokeKeyPairFromWifiAuth(@NonNull String);
- method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, conditional=true) public void setAccountManagementDisabled(@Nullable android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional=true) public boolean setApplicationHidden(@Nullable android.content.ComponentName, String, boolean);
method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
- method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimeEnabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimeEnabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
- method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@Nullable android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public void setCameraDisabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
- method public void setCommonCriteriaModeEnabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE, conditional=true) public void setCommonCriteriaModeEnabled(@Nullable android.content.ComponentName, boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI, conditional=true) public void setConfiguredNetworksLockdownState(@Nullable android.content.ComponentName, boolean);
method public void setCredentialManagerPolicy(@Nullable android.app.admin.PackagePolicy);
method @Deprecated public void setCrossProfileCalendarPackages(@NonNull android.content.ComponentName, @Nullable java.util.Set<java.lang.String>);
method @Deprecated public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
method @Deprecated public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
method public void setCrossProfilePackages(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
- method public void setDefaultSmsApplication(@NonNull android.content.ComponentName, @NonNull String);
+ method public void setDefaultDialerApplication(@NonNull String);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS, conditional=true) public void setDefaultSmsApplication(@Nullable android.content.ComponentName, @NonNull String);
method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
@@ -7928,12 +7930,12 @@
method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
- method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES, conditional=true) public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_KEYGUARD, conditional=true) public void setKeyguardDisabledFeatures(@Nullable android.content.ComponentName, int);
method public void setLocationEnabled(@NonNull android.content.ComponentName, boolean);
- method public void setLockTaskFeatures(@NonNull android.content.ComponentName, int);
- method public void setLockTaskPackages(@NonNull android.content.ComponentName, @NonNull String[]) throws java.lang.SecurityException;
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public void setLockTaskFeatures(@Nullable android.content.ComponentName, int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK, conditional=true) public void setLockTaskPackages(@Nullable android.content.ComponentName, @NonNull String[]) throws java.lang.SecurityException;
method public void setLogoutEnabled(@NonNull android.content.ComponentName, boolean);
method public void setLongSupportMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
method public void setManagedProfileCallerIdAccessPolicy(@Nullable android.app.admin.PackagePolicy);
@@ -7951,9 +7953,9 @@
method public void setNetworkLoggingEnabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setOrganizationColor(@NonNull android.content.ComponentName, int);
method public void setOrganizationId(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY) public void setOrganizationName(@Nullable android.content.ComponentName, @Nullable CharSequence);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, conditional=true) public void setOrganizationName(@Nullable android.content.ComponentName, @Nullable CharSequence);
method public void setOverrideApnsEnabled(@NonNull android.content.ComponentName, boolean);
- method @NonNull public String[] setPackagesSuspended(@NonNull android.content.ComponentName, @NonNull String[], boolean);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional=true) public String[] setPackagesSuspended(@Nullable android.content.ComponentName, @NonNull String[], boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional=true) public void setPasswordExpirationTimeout(@Nullable android.content.ComponentName, long);
method public void setPasswordHistoryLength(@NonNull android.content.ComponentName, int);
method @Deprecated public void setPasswordMinimumLength(@NonNull android.content.ComponentName, int);
@@ -7964,7 +7966,7 @@
method @Deprecated public void setPasswordMinimumSymbols(@NonNull android.content.ComponentName, int);
method @Deprecated public void setPasswordMinimumUpperCase(@NonNull android.content.ComponentName, int);
method @Deprecated public void setPasswordQuality(@NonNull android.content.ComponentName, int);
- method public boolean setPermissionGrantState(@NonNull android.content.ComponentName, @NonNull String, @NonNull String, int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, conditional=true) public boolean setPermissionGrantState(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, int);
method public void setPermissionPolicy(@NonNull android.content.ComponentName, int);
method public boolean setPermittedAccessibilityServices(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
@@ -7977,23 +7979,23 @@
method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional=true) public void setRequiredPasswordComplexity(int);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional=true) public void setRequiredStrongAuthTimeout(@Nullable android.content.ComponentName, long);
- method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional=true) public boolean setResetPasswordToken(@Nullable android.content.ComponentName, byte[]);
method public void setRestrictionsProvider(@NonNull android.content.ComponentName, @Nullable android.content.ComponentName);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, conditional=true) public void setScreenCaptureDisabled(@Nullable android.content.ComponentName, boolean);
method public void setSecureSetting(@NonNull android.content.ComponentName, String, String);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING, conditional=true) public void setSecurityLoggingEnabled(@Nullable android.content.ComponentName, boolean);
- method public void setShortSupportMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, conditional=true) public void setShortSupportMessage(@Nullable android.content.ComponentName, @Nullable CharSequence);
method public void setStartUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
- method public boolean setStatusBarDisabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_STATUS_BAR, conditional=true) public boolean setStatusBarDisabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public int setStorageEncryption(@NonNull android.content.ComponentName, boolean);
method public void setSystemSetting(@NonNull android.content.ComponentName, @NonNull String, String);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, conditional=true) public void setSystemUpdatePolicy(@NonNull android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
- method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public boolean setTime(@NonNull android.content.ComponentName, long);
- method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public boolean setTimeZone(@NonNull android.content.ComponentName, String);
+ method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public boolean setTime(@Nullable android.content.ComponentName, long);
+ method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public boolean setTimeZone(@Nullable android.content.ComponentName, String);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_KEYGUARD, conditional=true) public void setTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName, android.os.PersistableBundle);
- method public void setUninstallBlocked(@Nullable android.content.ComponentName, String, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional=true) public void setUninstallBlocked(@Nullable android.content.ComponentName, String, boolean);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, conditional=true) public void setUsbDataSignalingEnabled(boolean);
- method public void setUserControlDisabledPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional=true) public void setUserControlDisabledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
method public void setUserIcon(@NonNull android.content.ComponentName, android.graphics.Bitmap);
method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI, conditional=true) public void setWifiSsidPolicy(@Nullable android.app.admin.WifiSsidPolicy);
method public int startUserInBackground(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
@@ -8003,9 +8005,9 @@
method public void uninstallAllUserCaCerts(@Nullable android.content.ComponentName);
method public void uninstallCaCert(@Nullable android.content.ComponentName, byte[]);
method public boolean updateOverrideApn(@NonNull android.content.ComponentName, int, @NonNull android.telephony.data.ApnSetting);
- method public void wipeData(int);
- method public void wipeData(int, @NonNull CharSequence);
- method public void wipeDevice(int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA, conditional=true) public void wipeData(int);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA, conditional=true) public void wipeData(int, @NonNull CharSequence);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA, conditional=true) public void wipeDevice(int);
field public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
@@ -10243,7 +10245,6 @@
method @Deprecated public abstract int getWallpaperDesiredMinimumHeight();
method @Deprecated public abstract int getWallpaperDesiredMinimumWidth();
method public abstract void grantUriPermission(String, android.net.Uri, int);
- method public boolean isDeviceContext();
method public abstract boolean isDeviceProtectedStorage();
method public boolean isRestricted();
method public boolean isUiContext();
@@ -11355,7 +11356,8 @@
public class RestrictionsManager {
method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
method public android.content.Intent createLocalApprovalIntent();
- method public android.os.Bundle getApplicationRestrictions();
+ method @Deprecated public android.os.Bundle getApplicationRestrictions();
+ method @NonNull @WorkerThread public java.util.List<android.os.Bundle> getApplicationRestrictionsPerAdmin();
method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(String);
method public boolean hasRestrictionsProvider();
method public void notifyPermissionResponse(String, android.os.PersistableBundle);
@@ -15445,8 +15447,9 @@
ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
}
- public final class Gainmap {
+ public final class Gainmap implements android.os.Parcelable {
ctor public Gainmap(@NonNull android.graphics.Bitmap);
+ method public int describeContents();
method @NonNull public float getDisplayRatioForFullHdr();
method @NonNull public float[] getEpsilonHdr();
method @NonNull public float[] getEpsilonSdr();
@@ -15463,6 +15466,8 @@
method @NonNull public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
method @NonNull public void setRatioMax(float, float, float);
method @NonNull public void setRatioMin(float, float, float);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Gainmap> CREATOR;
}
public class HardwareBufferRenderer implements java.lang.AutoCloseable {
@@ -33748,7 +33753,7 @@
public class UserManager {
method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle);
- method @WorkerThread public android.os.Bundle getApplicationRestrictions(String);
+ method @Deprecated @WorkerThread public android.os.Bundle getApplicationRestrictions(String);
method public long getSerialNumberForUser(android.os.UserHandle);
method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public int getUserCount();
method public long getUserCreationTime(android.os.UserHandle);
@@ -41388,6 +41393,7 @@
method public void onEndOfSpeech();
method public void onError(int);
method public void onEvent(int, android.os.Bundle);
+ method public default void onLanguageDetection(@NonNull android.os.Bundle);
method public void onPartialResults(android.os.Bundle);
method public void onReadyForSpeech(android.os.Bundle);
method public void onResults(android.os.Bundle);
@@ -41445,6 +41451,7 @@
method public void error(int) throws android.os.RemoteException;
method @NonNull public android.content.AttributionSource getCallingAttributionSource();
method public int getCallingUid();
+ method public void languageDetection(@NonNull android.os.Bundle);
method public void partialResults(android.os.Bundle) throws android.os.RemoteException;
method public void readyForSpeech(android.os.Bundle) throws android.os.RemoteException;
method public void results(android.os.Bundle) throws android.os.RemoteException;
@@ -41502,10 +41509,14 @@
field public static final String EXTRA_CONFIDENCE_SCORES = "android.speech.extra.CONFIDENCE_SCORES";
field public static final String EXTRA_ENABLE_BIASING_DEVICE_CONTEXT = "android.speech.extra.ENABLE_BIASING_DEVICE_CONTEXT";
field public static final String EXTRA_ENABLE_FORMATTING = "android.speech.extra.ENABLE_FORMATTING";
+ field public static final String EXTRA_ENABLE_LANGUAGE_DETECTION = "android.speech.extra.ENABLE_LANGUAGE_DETECTION";
+ field public static final String EXTRA_ENABLE_LANGUAGE_SWITCH = "android.speech.extra.ENABLE_LANGUAGE_SWITCH";
field public static final String EXTRA_HIDE_PARTIAL_TRAILING_PUNCTUATION = "android.speech.extra.HIDE_PARTIAL_TRAILING_PUNCTUATION";
field public static final String EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE";
+ field public static final String EXTRA_LANGUAGE_DETECTION_ALLOWED_LANGUAGES = "android.speech.extra.LANGUAGE_DETECTION_ALLOWED_LANGUAGES";
field public static final String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL";
field public static final String EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE";
+ field public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES = "android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES";
field public static final String EXTRA_MASK_OFFENSIVE_WORDS = "android.speech.extra.MASK_OFFENSIVE_WORDS";
field public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
field public static final String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
@@ -41529,6 +41540,9 @@
field public static final String FORMATTING_OPTIMIZE_QUALITY = "quality";
field public static final String LANGUAGE_MODEL_FREE_FORM = "free_form";
field public static final String LANGUAGE_MODEL_WEB_SEARCH = "web_search";
+ field public static final String LANGUAGE_SWITCH_BALANCED = "balanced";
+ field public static final String LANGUAGE_SWITCH_HIGH_PRECISION = "high_precision";
+ field public static final String LANGUAGE_SWITCH_QUICK_RESPONSE = "quick_response";
field public static final int RESULT_AUDIO_ERROR = 5; // 0x5
field public static final int RESULT_CLIENT_ERROR = 2; // 0x2
field public static final int RESULT_NETWORK_ERROR = 4; // 0x4
@@ -41562,6 +41576,7 @@
method @MainThread public void stopListening();
method public void triggerModelDownload(@NonNull android.content.Intent);
field public static final String CONFIDENCE_SCORES = "confidence_scores";
+ field public static final String DETECTED_LANGUAGE = "detected_language";
field public static final int ERROR_AUDIO = 3; // 0x3
field public static final int ERROR_CANNOT_CHECK_SUPPORT = 14; // 0xe
field public static final int ERROR_CANNOT_LISTEN_TO_DOWNLOAD_EVENTS = 15; // 0xf
@@ -41577,9 +41592,20 @@
field public static final int ERROR_SERVER_DISCONNECTED = 11; // 0xb
field public static final int ERROR_SPEECH_TIMEOUT = 6; // 0x6
field public static final int ERROR_TOO_MANY_REQUESTS = 10; // 0xa
+ field public static final String LANGUAGE_DETECTION_CONFIDENCE_LEVEL = "language_detection_confidence_level";
+ field public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_CONFIDENT = 2; // 0x2
+ field public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_HIGHLY_CONFIDENT = 3; // 0x3
+ field public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_NOT_CONFIDENT = 1; // 0x1
+ field public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_UNKNOWN = 0; // 0x0
+ field public static final String LANGUAGE_SWITCH_RESULT = "language_switch_result";
+ field public static final int LANGUAGE_SWITCH_RESULT_FAILED = 2; // 0x2
+ field public static final int LANGUAGE_SWITCH_RESULT_NOT_ATTEMPTED = 0; // 0x0
+ field public static final int LANGUAGE_SWITCH_RESULT_SKIPPED_NO_MODEL = 3; // 0x3
+ field public static final int LANGUAGE_SWITCH_RESULT_SUCCEEDED = 1; // 0x1
field public static final String RECOGNITION_PARTS = "recognition_parts";
field public static final String RESULTS_ALTERNATIVES = "results_alternatives";
field public static final String RESULTS_RECOGNITION = "results_recognition";
+ field public static final String TOP_LOCALE_ALTERNATIVES = "top_locale_alternatives";
}
}
@@ -54143,6 +54169,7 @@
method public android.view.accessibility.AccessibilityWindowInfo getWindow();
method public int getWindowId();
method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean hasRequestTouchPassthrough();
method public boolean isAccessibilityFocused();
method public boolean isCheckable();
method public boolean isChecked();
@@ -54224,6 +54251,7 @@
method public void setQueryFromAppProcessEnabled(@NonNull android.view.View, boolean);
method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRequestTouchPassthrough(boolean);
method public void setScreenReaderFocusable(boolean);
method public void setScrollable(boolean);
method public void setSelected(boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2341971..fb544a9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -71,6 +71,7 @@
field public static final String BIND_RESUME_ON_REBOOT_SERVICE = "android.permission.BIND_RESUME_ON_REBOOT_SERVICE";
field public static final String BIND_ROTATION_RESOLVER_SERVICE = "android.permission.BIND_ROTATION_RESOLVER_SERVICE";
field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
+ field public static final String BIND_SATELLITE_SERVICE = "android.permission.BIND_SATELLITE_SERVICE";
field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
field public static final String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
@@ -325,6 +326,7 @@
field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE";
field public static final String SET_DEFAULT_ACCOUNT_FOR_CONTACTS = "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS";
field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
+ field public static final String SET_LOW_POWER_STANDBY_PORTS = "android.permission.SET_LOW_POWER_STANDBY_PORTS";
field public static final String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
field public static final String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
@@ -463,6 +465,7 @@
field public static final int config_systemAutomotiveCalendarSyncManager = 17039423; // 0x104003f
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
+ field public static final int config_systemCallStreaming;
field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039
field public static final int config_systemContacts = 17039403; // 0x104002b
field public static final int config_systemFinancedDeviceController;
@@ -576,6 +579,7 @@
field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
+ field public static final int HISTORY_FLAG_GET_ATTRIBUTION_CHAINS = 4; // 0x4
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
@@ -1296,11 +1300,10 @@
field @Deprecated public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
field public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = 2; // 0x2
- field public static final int EXEMPT_FROM_APP_STANDBY = 0; // 0x0
field public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = 1; // 0x1
- field public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4; // 0x4
field public static final int EXEMPT_FROM_HIBERNATION = 3; // 0x3
- field public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 5; // 0x5
+ field public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 4; // 0x4
+ field public static final int EXEMPT_FROM_SUSPENSION = 0; // 0x0
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -6874,7 +6877,7 @@
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS) public java.util.List<java.lang.Integer> getIndependentStreamTypes();
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
- method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleVolumeGroupVolume(int);
+ method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleVolumeForVolumeGroup(int);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -10054,7 +10057,7 @@
public class SharedConnectivityManager {
method public boolean connectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
- method public boolean disconnectTetherNetwork();
+ method public boolean disconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
method public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
method public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
@@ -10141,7 +10144,7 @@
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onConnectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public abstract void onConnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
- method public abstract void onDisconnectTetherNetwork();
+ method public abstract void onDisconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
method public abstract void onForgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public final void setKnownNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
method public final void setSettingsState(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
@@ -10660,6 +10663,7 @@
public final class PowerManager {
method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public java.util.List<android.os.PowerManager.LowPowerStandbyPortDescription> getActiveLowPowerStandbyPorts();
method @NonNull public android.os.BatterySaverPolicyConfig getFullPowerSavePolicy();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public android.os.PowerManager.LowPowerStandbyPolicy getLowPowerStandbyPolicy();
method public int getPowerSaveModeTrigger();
@@ -10667,6 +10671,7 @@
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressed();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public boolean isLowPowerStandbySupported();
+ method @NonNull @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS) public android.os.PowerManager.LowPowerStandbyPortsLock newLowPowerStandbyPortsLock(@NonNull java.util.List<android.os.PowerManager.LowPowerStandbyPortDescription>);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
method @RequiresPermission(anyOf={android.Manifest.permission.BATTERY_PREDICTION, android.Manifest.permission.DEVICE_POWER}) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
@@ -10678,6 +10683,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
+ field @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY) public static final String ACTION_LOW_POWER_STANDBY_PORTS_CHANGED = "android.os.action.LOW_POWER_STANDBY_PORTS_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
field public static final String REBOOT_USERSPACE = "userspace";
@@ -10700,6 +10706,25 @@
method @NonNull public String getIdentifier();
}
+ public static final class PowerManager.LowPowerStandbyPortDescription {
+ ctor public PowerManager.LowPowerStandbyPortDescription(int, int, int);
+ ctor public PowerManager.LowPowerStandbyPortDescription(int, int, int, @Nullable android.net.LinkAddress);
+ method @Nullable public android.net.LinkAddress getBindAddress();
+ method public int getPortMatcher();
+ method public int getPortNumber();
+ method public int getProtocol();
+ field public static final int MATCH_PORT_LOCAL = 1; // 0x1
+ field public static final int MATCH_PORT_REMOTE = 2; // 0x2
+ field public static final int PROTOCOL_TCP = 1; // 0x1
+ field public static final int PROTOCOL_UDP = 2; // 0x2
+ }
+
+ public final class PowerManager.LowPowerStandbyPortsLock {
+ method @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS) public void acquire();
+ method protected void finalize();
+ method @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS) public void release();
+ }
+
@Deprecated public class PowerWhitelistManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4e364a2..d5ced04 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -627,6 +627,13 @@
method @NonNull public android.app.admin.ResolutionMechanism<V> getResolutionMechanism();
}
+ public abstract class PolicyUpdateReceiver extends android.content.BroadcastReceiver {
+ field public static final String EXTRA_POLICY_BUNDLE_KEY = "android.app.admin.extra.POLICY_BUNDLE_KEY";
+ field public static final String EXTRA_POLICY_KEY = "android.app.admin.extra.POLICY_KEY";
+ field public static final String EXTRA_POLICY_TARGET_USER_ID = "android.app.admin.extra.POLICY_TARGET_USER_ID";
+ field public static final String EXTRA_POLICY_UPDATE_RESULT_KEY = "android.app.admin.extra.POLICY_UPDATE_RESULT_KEY";
+ }
+
public abstract class ResolutionMechanism<V> implements android.os.Parcelable {
}
@@ -642,6 +649,13 @@
field @NonNull public static final android.app.admin.StringSetUnion STRING_SET_UNION;
}
+ public final class TargetUser {
+ field public static final int GLOBAL_USER_ID = -3; // 0xfffffffd
+ field public static final int LOCAL_USER_ID = -1; // 0xffffffff
+ field public static final int PARENT_USER_ID = -2; // 0xfffffffe
+ field public static final int UNKNOWN_USER_ID = -3; // 0xfffffffd
+ }
+
public final class TopPriority<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
method @NonNull public java.util.List<android.app.admin.Authority> getHighestToLowestPriorityAuthorities();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index c4fd991..52e2024 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2075,7 +2075,9 @@
public static final String OPSTR_USE_FULL_SCREEN_INTENT = "android:use_full_screen_intent";
/**
- * Prevent an app from being placed into hibernation.
+ * Prevent an app from being placed into hibernation.
+ *
+ * Only to be used by the system.
*
* @hide
*/
@@ -2084,7 +2086,9 @@
"android:system_exempt_from_hibernation";
/**
- * Prevent an app from being suspended.
+ * Prevent an app from being suspended.
+ *
+ * Only to be used by the system.
*
* @hide
*/
@@ -2583,7 +2587,8 @@
"SYSTEM_EXEMPT_FROM_APP_STANDBY").build(),
new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
- "SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS").build(),
+ "SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS")
+ .setDisableReset(true).build(),
new AppOpInfo.Builder(OP_READ_WRITE_HEALTH_DATA, OPSTR_READ_WRITE_HEALTH_DATA,
"READ_WRITE_HEALTH_DATA").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_FOREGROUND_SERVICE_SPECIAL_USE,
@@ -2591,7 +2596,8 @@
.setPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE).build(),
new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
- "SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS").build(),
+ "SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS")
+ .setDisableReset(true).build(),
new AppOpInfo.Builder(
OP_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
@@ -2599,7 +2605,8 @@
.build(),
new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
- "SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION").build(),
+ "SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION")
+ .setDisableReset(true).build(),
new AppOpInfo.Builder(
OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
@@ -2616,7 +2623,8 @@
.build(),
new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_HIBERNATION,
OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION,
- "SYSTEM_EXEMPT_FROM_HIBERNATION").build(),
+ "SYSTEM_EXEMPT_FROM_HIBERNATION")
+ .setDisableReset(true).build(),
new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_SUSPENSION,
OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION,
"SYSTEM_EXEMPT_FROM_SUSPENSION")
@@ -4604,10 +4612,9 @@
* Flag for querying app op history: assemble attribution chains, and attach the last visible
* node in the chain to the start as a proxy info. This only applies to discrete accesses.
*
- * TODO 191512294: Add to @SystemApi
- *
* @hide
*/
+ @SystemApi
public static final int HISTORY_FLAG_GET_ATTRIBUTION_CHAINS = 1 << 2;
/**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bed75db..e45944e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3068,18 +3068,6 @@
}
@Override
- public boolean isDeviceContext() {
- if (mIsExplicitDeviceId) {
- if (mDeviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT) {
- return true;
- }
- VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
- return vdm.isValidVirtualDeviceId(mDeviceId);
- }
- return isAssociatedWithDisplay();
- }
-
- @Override
public void registerDeviceIdChangeListener(@NonNull @CallbackExecutor Executor executor,
@NonNull IntConsumer listener) {
Objects.requireNonNull(executor, "executor cannot be null");
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index bb91ecd..5cad1ae 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -43,8 +43,10 @@
import android.os.SystemClock;
import android.os.TestLooperManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import android.view.Display;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -93,6 +95,8 @@
private static final long CONNECT_TIMEOUT_MILLIS = 5000;
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
/**
* @hide
*/
@@ -1124,10 +1128,44 @@
newEvent.setTime(downTime, eventTime);
newEvent.setSource(source);
newEvent.setFlags(event.getFlags() | KeyEvent.FLAG_FROM_SYSTEM);
+ setDisplayIfNeeded(newEvent);
+
InputManager.getInstance().injectInputEvent(newEvent,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
+ private void setDisplayIfNeeded(KeyEvent event) {
+ if (!UserManager.isVisibleBackgroundUsersEnabled()) {
+ return;
+ }
+ // In devices that support visible background users visible, the display id must be set to
+ // reflect the display the user was started visible on, otherwise the event would be sent to
+ // the main display (which would most likely fail the test).
+ int eventDisplayId = event.getDisplayId();
+ if (eventDisplayId != Display.INVALID_DISPLAY) {
+ if (VERBOSE) {
+ Log.v(TAG, "setDisplayIfNeeded(" + event + "): not changing display id as it's "
+ + "explicitly set to " + eventDisplayId);
+ }
+ return;
+ }
+
+ UserManager userManager = mInstrContext.getSystemService(UserManager.class);
+ int userDisplayId = userManager.getDisplayIdAssignedToUser();
+ if (VERBOSE) {
+ Log.v(TAG, "setDisplayIfNeeded(" + event + "): eventDisplayId=" + eventDisplayId
+ + ", user=" + mInstrContext.getUser() + ", userDisplayId=" + userDisplayId);
+ }
+ if (userDisplayId == Display.INVALID_DISPLAY) {
+ Log.e(TAG, "setDisplayIfNeeded(" + event + "): UserManager returned INVALID_DISPLAY as "
+ + "display assigned to user " + mInstrContext.getUser());
+ return;
+
+ }
+
+ event.setDisplayId(userDisplayId);
+ }
+
/**
* Sends up and down key events with the given key code to the currently focused window, and
* waits for it to be processed.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d4151e5..3a3ad8ce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -712,6 +712,15 @@
*/
public static final int FLAG_NO_DISMISS = 0x00002000;
+ /**
+ * Bit to be bitwise-ORed into the {@link #flags} field that should be
+ * set by the system if the app that sent this notification does not have the permission to send
+ * full screen intents.
+ *
+ * This flag is for internal use only; applications cannot set this flag directly.
+ * @hide
+ */
+ public static final int FLAG_FSI_REQUESTED_BUT_DENIED = 0x00004000;
private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList(
BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
@@ -5749,7 +5758,10 @@
List<Notification.Action> nonContextualActions = getNonContextualActions();
int numActions = Math.min(nonContextualActions.size(), MAX_ACTION_BUTTONS);
- boolean emphazisedMode = mN.fullScreenIntent != null || p.mCallStyleActions;
+ boolean emphazisedMode = mN.fullScreenIntent != null
+ || p.mCallStyleActions
+ || ((mN.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0);
+
if (p.mCallStyleActions) {
// Clear view padding to allow buttons to start on the left edge.
// This must be done before 'setEmphasizedMode' which sets top/bottom margins.
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index e1ee3e0..e0f5fb4 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -428,30 +428,18 @@
throw new IllegalArgumentException(msg);
}
- // Whenever creation or retrieval of a mutable implicit PendingIntent occurs:
- // - For apps with target SDK >= U, throw an IllegalArgumentException for
- // security reasons.
- // - Otherwise, warn that it will be blocked from target SDK U onwards.
- if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
- if (Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
- String msg = packageName + ": Targeting U+ (version "
- + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows"
- + " creating or retrieving a PendingIntent with FLAG_MUTABLE,"
- + " an implicit Intent within and without FLAG_NO_CREATE and"
- + " FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for"
- + " security reasons. To retrieve an already existing"
- + " PendingIntent, use FLAG_NO_CREATE, however, to create a"
- + " new PendingIntent with an implicit Intent use"
- + " FLAG_IMMUTABLE.";
- throw new IllegalArgumentException(msg);
- } else {
- String msg = "New mutable implicit PendingIntent: pkg=" + packageName
- + ", action=" + intent.getAction()
- + ", featureId=" + context.getAttributionTag()
- + ". This will be blocked once the app targets U+"
- + " for security reasons.";
- Log.w(TAG, new RuntimeException(msg));
- }
+ // For apps with target SDK < U, warn that creation or retrieval of a mutable
+ // implicit PendingIntent will be blocked from target SDK U onwards for security
+ // reasons. The block itself happens on the server side, but this warning has to
+ // stay here to preserve the client side stack trace for app developers.
+ if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)
+ && !Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
+ String msg = "New mutable implicit PendingIntent: pkg=" + packageName
+ + ", action=" + intent.getAction()
+ + ", featureId=" + context.getAttributionTag()
+ + ". This will be blocked once the app targets U+"
+ + " for security reasons.";
+ Log.w(TAG, new StackTrace(msg));
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 94a3bbb..b6a8327 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,19 +18,29 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_KEYGUARD;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MTE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_STATUS_BAR;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;
@@ -3886,18 +3896,17 @@
public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1;
/**
- * Prevent an app from being placed into app standby buckets, such that it will not be subject
- * to device resources restrictions as a result of app standby buckets.
+ * Prevent an app from being suspended.
*
* @hide
*/
@SystemApi
- public static final int EXEMPT_FROM_APP_STANDBY = 0;
+ public static final int EXEMPT_FROM_SUSPENSION = 0;
/**
* Prevent an app from dismissible notifications. Starting from Android U, notifications with
* the ongoing parameter can be dismissed by a user on an unlocked device. An app with
- * this exemption can create non-dismissable notifications.
+ * this exemption can create non-dismissible notifications.
*
* @hide
*/
@@ -3921,15 +3930,6 @@
public static final int EXEMPT_FROM_HIBERNATION = 3;
/**
- * Exempt an app from the start foreground service from background with while in user permission
- * restriction.
- *
- * @hide
- */
- @SystemApi
- public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4;
-
- /**
* Exempt an app from all power-related restrictions, including app standby and doze.
* In addition, the app will be able to start foreground services from the background,
* and the user will not be able to stop foreground services run by the app.
@@ -3937,7 +3937,7 @@
* @hide
*/
@SystemApi
- public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 5;
+ public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 4;
/**
* Exemptions to platform restrictions, given to an application through
@@ -3946,11 +3946,10 @@
* @hide
*/
@IntDef(prefix = { "EXEMPT_FROM_"}, value = {
- EXEMPT_FROM_APP_STANDBY,
+ EXEMPT_FROM_SUSPENSION,
EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
EXEMPT_FROM_HIBERNATION,
- EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
EXEMPT_FROM_POWER_RESTRICTIONS
})
@Retention(RetentionPolicy.SOURCE)
@@ -5967,9 +5966,11 @@
}
/**
- * Called by a profile or device owner to provision a token which can later be used to reset the
- * device lockscreen password (if called by device owner), or managed profile challenge (if
- * called by profile owner), via {@link #resetPasswordWithToken}.
+ * Called by a profile owner, device owner or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD} to provision a token
+ * which can later be used to reset the device lockscreen password (if called by on the main or
+ * system user), or managed profile challenge (if called on a managed profile), via
+ * {@link #resetPasswordWithToken}.
* <p>
* If the user currently has a lockscreen password, the provisioned token will not be
* immediately usable; it only becomes active after the user performs a confirm credential
@@ -5992,19 +5993,23 @@
* <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
* reset token is not set and this method returns false.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param token a secure token a least 32-byte long, which must be generated by a
* cryptographically strong random number generator.
* @return true if the operation is successful, false otherwise.
- * @throws SecurityException if admin is not a device or profile owner.
+ * @throws SecurityException if admin is not a device or profile owner and the caller does
+ * not hold the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}.
* @throws IllegalArgumentException if the supplied token is invalid.
*/
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional = true)
+ public boolean setResetPasswordToken(@Nullable ComponentName admin, byte[] token) {
throwIfParentInstance("setResetPasswordToken");
if (mService != null) {
try {
- return mService.setResetPasswordToken(admin, token);
+ return mService.setResetPasswordToken(admin, mContext.getPackageName(), token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6013,22 +6018,27 @@
}
/**
- * Called by a profile or device owner to revoke the current password reset token.
+ * Called by a profile, device owner or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}
+ * to revoke the current password reset token.
*
* <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this
* method has no effect - the reset token should not have been set in the first place - and
* false is returned.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return true if the operation is successful, false otherwise.
- * @throws SecurityException if admin is not a device or profile owner.
+ * @throws SecurityException if admin is not a device or profile owner and if the caller does
+ * not the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}.
*/
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public boolean clearResetPasswordToken(ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional = true)
+ public boolean clearResetPasswordToken(@Nullable ComponentName admin) {
throwIfParentInstance("clearResetPasswordToken");
if (mService != null) {
try {
- return mService.clearResetPasswordToken(admin);
+ return mService.clearResetPasswordToken(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6037,22 +6047,27 @@
}
/**
- * Called by a profile or device owner to check if the current reset password token is active.
+ * Called by a profile, device owner or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}
+ * to check if the current reset password token is active.
*
* <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature,
* false is always returned.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return true if the token is active, false otherwise.
- * @throws SecurityException if admin is not a device or profile owner.
+ * @throws SecurityException if admin is not a device or profile owner and not a holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}
* @throws IllegalStateException if no token has been set.
*/
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public boolean isResetPasswordTokenActive(ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional = true)
+ public boolean isResetPasswordTokenActive(@Nullable ComponentName admin) {
throwIfParentInstance("isResetPasswordTokenActive");
if (mService != null) {
try {
- return mService.isResetPasswordTokenActive(admin);
+ return mService.isResetPasswordTokenActive(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6061,8 +6076,10 @@
}
/**
- * Called by device or profile owner to force set a new device unlock password or a managed
- * profile challenge on current user. This takes effect immediately.
+ * Called by device owner, profile owner or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}to force set a new
+ * device unlock password or a managed profile challenge on current user. This takes effect
+ * immediately.
* <p>
* Unlike {@link #resetPassword}, this API can change the password even before the user or
* device is unlocked or decrypted. The supplied token must have been previously provisioned via
@@ -6080,7 +6097,8 @@
* <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature,
* calling this methods has no effect - the password is always empty - and false is returned.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param password The new password for the user. {@code null} or empty clears the password.
* @param token the password reset token previously provisioned by
* {@link #setResetPasswordToken}.
@@ -6088,16 +6106,19 @@
* {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
* @return Returns true if the password was applied, or false if it is not acceptable for the
* current constraints.
- * @throws SecurityException if admin is not a device or profile owner.
+ * @throws SecurityException if admin is not a device or profile owner and the caller does not
+ * hold the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RESET_PASSWORD}.
* @throws IllegalStateException if the provided token is not valid.
*/
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public boolean resetPasswordWithToken(@NonNull ComponentName admin, String password,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RESET_PASSWORD, conditional = true)
+ public boolean resetPasswordWithToken(@Nullable ComponentName admin, String password,
byte[] token, int flags) {
throwIfParentInstance("resetPassword");
if (mService != null) {
try {
- return mService.resetPasswordWithToken(admin, password, token, flags);
+ return mService.resetPasswordWithToken(admin, mContext.getPackageName(), password,
+ token, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6405,15 +6426,18 @@
* @param flags Bit mask of additional options: currently supported flags are
* {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA},
* {@link #WIPE_EUICC} and {@link #WIPE_SILENTLY}.
- * @throws SecurityException if the calling application does not own an active
- * administrator
- * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} and is
- * not granted the
- * {@link android.Manifest.permission#MASTER_CLEAR} permission.
+ * @throws SecurityException if the calling application does not own an active
+ * administrator
+ * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} and is
+ * not granted the
+ * {@link android.Manifest.permission#MASTER_CLEAR} or
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_WIPE_DATA}
+ * permissions.
* @throws IllegalStateException if called on last full-user or system-user
* @see #wipeDevice(int)
* @see #wipeData(int, CharSequence)
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_WIPE_DATA, conditional = true)
public void wipeData(int flags) {
wipeDataInternal(flags,
/* wipeReasonForUser= */ "",
@@ -6447,13 +6471,15 @@
* presented to the user.
* @throws SecurityException if the calling application does not own an active administrator
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} and is not granted the
- * {@link android.Manifest.permission#MASTER_CLEAR} permission.
+ * {@link android.Manifest.permission#MASTER_CLEAR} or
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_WIPE_DATA} permissions.
* @throws IllegalArgumentException if the input reason string is null or empty, or if
* {@link #WIPE_SILENTLY} is set.
* @throws IllegalStateException if called on last full-user or system-user
* @see #wipeDevice(int)
* @see #wipeData(int)
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_WIPE_DATA, conditional = true)
public void wipeData(int flags, @NonNull CharSequence reason) {
Objects.requireNonNull(reason, "reason string is null");
Preconditions.checkStringNotEmpty(reason, "reason string is empty");
@@ -6473,13 +6499,17 @@
* {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA},
* {@link #WIPE_EUICC} and {@link #WIPE_SILENTLY}.
* @throws SecurityException if the calling application does not own an active administrator
- * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} and is not
- * granted the {@link android.Manifest.permission#MASTER_CLEAR}
- * permission.
+ * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} and is not
+ * granted the {@link android.Manifest.permission#MASTER_CLEAR}
+ * or both the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_WIPE_DATA} and
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}
+ * permissions.
* @see #wipeData(int)
* @see #wipeData(int, CharSequence)
*/
// TODO(b/255323293) Add host-side tests
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_WIPE_DATA, conditional = true)
public void wipeDevice(int flags) {
wipeDataInternal(flags,
/* wipeReasonForUser= */ "",
@@ -6499,8 +6529,8 @@
boolean factoryReset) {
if (mService != null) {
try {
- mService.wipeDataWithReason(flags, wipeReasonForUser, mParentInstance,
- factoryReset);
+ mService.wipeDataWithReason(mContext.getPackageName(), flags, wipeReasonForUser,
+ mParentInstance, factoryReset);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -7295,6 +7325,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
* All apps within the profile will be able to access the certificate and use the private key,
* given direct user approval.
@@ -7317,17 +7349,19 @@
* revoked.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param privKey The private key to install.
* @param cert The certificate to install.
* @param alias The private key alias under which to install the certificate. If a certificate
* with that alias already exists, it will be overwritten.
* @return {@code true} if the keys were installed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
+ * owner, or {@code admin} is null and the calling application does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate cert, @NonNull String alias) {
return installKeyPair(admin, privKey, new Certificate[] {cert}, alias, false);
@@ -7341,6 +7375,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
* All apps within the profile will be able to access the certificate chain and use the private
* key, given direct user approval.
@@ -7361,7 +7397,7 @@
* revoked.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param privKey The private key to install.
* @param certs The certificate chain to install. The chain should start with the leaf
* certificate and include the chain of trust in order. This will be returned by
@@ -7373,11 +7409,13 @@
* approval.
* @return {@code true} if the keys were installed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
+ * owner, or {@code admin} is null and the calling application does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @see android.security.KeyChain#getCertificateChain
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
int flags = INSTALLKEY_SET_USER_SELECTABLE;
@@ -7395,6 +7433,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
* All apps within the profile will be able to access the certificate chain and use the
* private key, given direct user approval (if the user is allowed to select the private key).
@@ -7421,7 +7461,7 @@
* revoked.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param privKey The private key to install.
* @param certs The certificate chain to install. The chain should start with the leaf
* certificate and include the chain of trust in order. This will be returned by
@@ -7432,13 +7472,15 @@
* and set the key to be user-selectable. See {@link #INSTALLKEY_SET_USER_SELECTABLE} and
* {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}.
* @return {@code true} if the keys were installed, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner, or {@code admin} is null but the calling application is not a delegated
- * certificate installer or credential management app.
+ * @throws SecurityException if {@code admin} is not {@code null} and not a device or
+ * profile owner, or {@code admin} is null but the calling application is not a
+ * delegated certificate installer, credential management app and does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @see android.security.KeyChain#getCertificateChain
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate[] certs, @NonNull String alias, int flags) {
throwIfParentInstance("installKeyPair");
@@ -7474,6 +7516,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
*
* <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
@@ -7481,15 +7525,17 @@
* {@code null}. Note, there can only be a credential management app on an unmanaged device.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param alias The private key alias under which the certificate is installed.
* @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner, or {@code admin} is null but the calling application is not a delegated
- * certificate installer or credential management app.
+ * @throws SecurityException if {@code admin} is not {@code null} and not a device owner or
+ * profile owner, or {@code admin} is null but the calling application is not a
+ * delegated certificate installer, credential management app and does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
throwIfParentInstance("removeKeyPair");
try {
@@ -7508,6 +7554,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
*
* If called by the credential management app, the alias must exist in the credential
@@ -7516,10 +7564,12 @@
* @param alias The alias under which the key pair is installed.
* @return {@code true} if a key pair with this alias exists, {@code false} otherwise.
* @throws SecurityException if the caller is not a device or profile owner, a delegated
- * certificate installer or the credential management app.
+ * certificate installer, the credential management app and does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean hasKeyPair(@NonNull String alias) {
throwIfParentInstance("hasKeyPair");
try {
@@ -7536,6 +7586,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
* If the device supports key generation via secure hardware, this method is useful for
* creating a key in KeyChain that never left the secure hardware. Access to the key is
@@ -7566,19 +7618,23 @@
* supports these features, refer to {@link #isDeviceIdAttestationSupported()} and
* {@link #isUniqueDeviceAttestationSupported()}.
*
- * <p>Device owner, profile owner, their delegated certificate installer and the credential
- * management app can use {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device
- * information including manufacturer, model, brand, device and product in the attestation
- * record.
- * Only device owner, profile owner on an organization-owned device or affiliated user, and
- * their delegated certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI}
- * and {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial
- * number, IMEI and MEID correspondingly), if supported by the device
- * (see {@link #isDeviceIdAttestationSupported()}).
- * Additionally, device owner, profile owner on an organization-owned device and their delegated
- * certificate installers can also request the attestation record to be signed using an
- * individual attestation certificate by specifying the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION}
- * flag (if supported by the device, see {@link #isUniqueDeviceAttestationSupported()}).
+ * <p>Device owner, profile owner, their delegated certificate installer, the credential
+ * management app or an app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission can use
+ * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information including
+ * manufacturer, model, brand, device and product in the attestation record.
+ * Only device owner, profile owner on an organization-owned device or affiliated user, their
+ * delegated certificate installers or an app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission can use
+ * {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request unique
+ * device identifiers to be attested (the serial number, IMEI and MEID correspondingly),
+ * if supported by the device (see {@link #isDeviceIdAttestationSupported()}).
+ * Additionally, device owner, profile owner on an organization-owned device, their delegated
+ * certificate installers and an app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission can also
+ * request the attestation record to be signed using an individual attestation certificate by
+ * specifying the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION} flag (if supported by the device,
+ * see {@link #isUniqueDeviceAttestationSupported()}).
* <p>
* If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
* is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
@@ -7587,7 +7643,7 @@
* key generation is done in StrongBox.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
* @param keySpec Specification of the key to generate, see
* {@link java.security.KeyPairGenerator}.
@@ -7603,12 +7659,14 @@
* If any flag is specified, then an attestation challenge must be included in the
* {@code keySpec}.
* @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
- * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner, or {@code admin} is null but the calling application is not a delegated
- * certificate installer or credential management app. If Device ID attestation is
- * requested (using {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} or
- * {@link #ID_TYPE_MEID}), the caller must be the Device Owner or the Certificate
- * Installer delegate.
+ * @throws SecurityException if {@code admin} is not {@code null} and not a device owner or
+ * profile owner, or {@code admin} is null but the calling application is not a
+ * delegated certificate installer, credential management app and does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
+ * If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
+ * {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner,
+ * the Certificate Installer delegate or have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
* @throws IllegalArgumentException in the following cases:
* <p>
* <ul>
@@ -7624,6 +7682,7 @@
* specified in {@code keySpec} but the device does not have one.
* @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
@NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec,
@AttestationIdType int idAttestationFlags) {
@@ -7890,6 +7949,8 @@
* <li>Profile owner</li>
* <li>Delegated certificate installer</li>
* <li>Credential management app</li>
+ * <li>An app that holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission</li>
* </ul>
*
* <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
@@ -7897,7 +7958,7 @@
* {@code null}. Note, there can only be a credential management app on an unmanaged device.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if the caller is not a device admin.
* @param alias The private key alias under which to install the certificate. The {@code alias}
* should denote an existing private key. If a certificate with that alias already
* exists, it will be overwritten.
@@ -7910,10 +7971,12 @@
* {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}.
* @return {@code true} if the provided {@code alias} exists and the certificates has been
* successfully associated with it, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner, or {@code admin} is null but the calling application is not a delegated
- * certificate installer or credential management app.
+ * @throws SecurityException if {@code admin} is not {@code null} and not a device owner or
+ * profile owner, or {@code admin} is null but the calling application is not a
+ * delegated certificate installer, credential management app and does not have the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
public boolean setKeyPairCertificate(@Nullable ComponentName admin,
@NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) {
throwIfParentInstance("setKeyPairCertificate");
@@ -7934,7 +7997,6 @@
return false;
}
-
/**
* @return the alias of a given CA certificate in the certificate store, or {@code null} if it
* doesn't exist.
@@ -8300,14 +8362,15 @@
* <p>
* This method can be called on the {@link DevicePolicyManager} instance,
* returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be
- * the profile owner of an organization-owned managed profile.
+ * the profile owner of an organization-owned managed profile
* <p>
* If the caller is device owner, then the restriction will be applied to all users. If
* called on the parent instance, then the restriction will be applied on the personal profile.
* <p>
* The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has
- * not, a security exception will be thrown.
+ * not, a security exception will be thrown, or the caller must hold the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CAMERA}.
* <p>
* <b>Note</b>, this policy type is deprecated for legacy device admins since
* {@link android.os.Build.VERSION_CODES#Q}. On Android
@@ -8323,7 +8386,8 @@
the caller is not a device admin
* @param disabled Whether or not the camera should be disabled.
* @throws SecurityException if {@code admin} is not an active administrator or does not use
- * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
+ * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} and the caller does not hold
+ * the permisisons {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CAMERA}.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
@@ -8343,11 +8407,14 @@
* <p>
* This method can be called on the {@link DevicePolicyManager} instance,
* returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be
- * the profile owner of an organization-owned managed profile.
+ * the profile owner of an organization-owned managed profile or the caller has been granted
+ * the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CAMERA} and the
+ * cross-user permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}.
*
- * @param admin The name of the admin component to check, or {@code null} to check whether any admins
- * have disabled the camera
+ * @param admin The name of the admin component to check, or {@code null} to check whether any
+ * admins have disabled the camera
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
public boolean getCameraDisabled(@Nullable ComponentName admin) {
return getCameraDisabled(admin, myUserId());
}
@@ -8357,7 +8424,8 @@
public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getCameraDisabled(admin, userHandle, mParentInstance);
+ return mService.getCameraDisabled(admin, mContext.getPackageName(), userHandle,
+ mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8616,17 +8684,18 @@
* no user will be able set the date and time. Instead, the network date
* and time will be used.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param enabled Whether time should be obtained automatically from the network or not.
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile or a holder of the
* permission {@link android.Manifest.permission#SET_TIME}.
*/
@RequiresPermission(value = SET_TIME, conditional = true)
- public void setAutoTimeEnabled(@NonNull ComponentName admin, boolean enabled) {
+ public void setAutoTimeEnabled(@Nullable ComponentName admin, boolean enabled) {
if (mService != null) {
try {
- mService.setAutoTimeEnabled(admin, enabled);
+ mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8640,16 +8709,18 @@
* are also able to call this method if they hold the permission
*{@link android.Manifest.permission#SET_TIME}.
*
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return true if auto time is enabled on the device.
* @throws SecurityException if the caller is not a device owner, a profile
* owner for the primary user, or a profile owner of an organization-owned managed profile or a
* holder of the permission {@link android.Manifest.permission#SET_TIME}.
*/
@RequiresPermission(anyOf = {SET_TIME, QUERY_ADMIN_POLICY}, conditional = true)
- public boolean getAutoTimeEnabled(@NonNull ComponentName admin) {
+ public boolean getAutoTimeEnabled(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getAutoTimeEnabled(admin);
+ return mService.getAutoTimeEnabled(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8669,7 +8740,8 @@
* no user will be able set the date and time zone. Instead, the network date
* and time zone will be used.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with or Null if the
+ * caller is not a device admin.
* @param enabled Whether time zone should be obtained automatically from the network or not.
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile or a holder of the
@@ -8677,11 +8749,11 @@
*/
@SupportsCoexistence
@RequiresPermission(value = SET_TIME_ZONE, conditional = true)
- public void setAutoTimeZoneEnabled(@NonNull ComponentName admin, boolean enabled) {
+ public void setAutoTimeZoneEnabled(@Nullable ComponentName admin, boolean enabled) {
throwIfParentInstance("setAutoTimeZone");
if (mService != null) {
try {
- mService.setAutoTimeZoneEnabled(admin, enabled);
+ mService.setAutoTimeZoneEnabled(admin, mContext.getPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8695,17 +8767,19 @@
* are also able to call this method if they hold the permission
*{@link android.Manifest.permission#SET_TIME}.
*
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return true if auto time zone is enabled on the device.
* @throws SecurityException if the caller is not a device owner, a profile
* owner for the primary user, or a profile owner of an organization-owned managed profile or a
* holder of the permission {@link android.Manifest.permission#SET_TIME_ZONE}.
*/
@RequiresPermission(anyOf = {SET_TIME_ZONE, QUERY_ADMIN_POLICY}, conditional = true)
- public boolean getAutoTimeZoneEnabled(@NonNull ComponentName admin) {
+ public boolean getAutoTimeZoneEnabled(@Nullable ComponentName admin) {
throwIfParentInstance("getAutoTimeZone");
if (mService != null) {
try {
- return mService.getAutoTimeZoneEnabled(admin);
+ return mService.getAutoTimeZoneEnabled(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9426,9 +9500,12 @@
}
/**
- * Called by device or profile owners to suspend packages for this user. This function can be
- * called by a device owner, profile owner, or by a delegate given the
- * {@link #DELEGATION_PACKAGE_ACCESS} scope via {@link #setDelegatedScopes}.
+ * Called by device or profile owners or holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PACKAGE_STATE}.
+ * to suspend packages for this user. This function can be
+ * called by a device owner, profile owner, by a delegate given the
+ * {@link #DELEGATION_PACKAGE_ACCESS} scope via {@link #setDelegatedScopes} or by holders of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PACKAGE_STATE}.
* <p>
* A suspended package will not be able to start activities. Its notifications will be hidden,
* it will not show up in recents, will not be able to show toasts or dialogs or ring the
@@ -9442,18 +9519,22 @@
* package installer, the required package uninstaller, the required package verifier, the
* default dialer, and the permission controller.
*
- * @param admin The name of the admin component to check, or {@code null} if the caller is a
- * package access delegate.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageNames The package names to suspend or unsuspend.
* @param suspended If set to {@code true} than the packages will be suspended, if set to
* {@code false} the packages will be unsuspended.
* @return an array of package names for which the suspended status is not set as requested in
* this method.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or has not been
+ * granted the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PACKAGE_STATE}.
* @see #setDelegatedScopes
* @see #DELEGATION_PACKAGE_ACCESS
*/
- public @NonNull String[] setPackagesSuspended(@NonNull ComponentName admin,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional = true)
+ @NonNull
+ public String[] setPackagesSuspended(@Nullable ComponentName admin,
@NonNull String[] packageNames, boolean suspended) {
throwIfParentInstance("setPackagesSuspended");
if (mService != null) {
@@ -9470,19 +9551,23 @@
/**
* Determine if a package is suspended. This function can be called by a device owner, profile
* owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
- * {@link #setDelegatedScopes}.
+ * {@link #setDelegatedScopes} or by holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PACKAGE_STATE}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if the caller is a package access delegate.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The name of the package to retrieve the suspended status of.
* @return {@code true} if the package is suspended or {@code false} if the package is not
* suspended, could not be found or an error occurred.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or has not been
+ * granted the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PACKAGE_STATE}.
* @throws NameNotFoundException if the package could not be found.
* @see #setDelegatedScopes
* @see #DELEGATION_PACKAGE_ACCESS
*/
- public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional = true)
+ public boolean isPackageSuspended(@Nullable ComponentName admin, String packageName)
throws NameNotFoundException {
throwIfParentInstance("isPackageSuspended");
if (mService != null) {
@@ -9728,10 +9813,11 @@
}
/**
- * Called by a profile owner or device owner to set a default activity that the system selects
- * to handle intents that match the given {@link IntentFilter}. This activity will remain the
- * default intent handler even if the set of potential event handlers for the intent filter
- * changes and if the intent preferences are reset.
+ * Called by a profile owner or device owner or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}. to set a default activity
+ * that the system selects to handle intents that match the given {@link IntentFilter}.
+ * This activity will remain the default intent handler even if the set of potential event
+ * handlers for the intent filter changes and if the intent preferences are reset.
* <p>
* Note that the caller should still declare the activity in the manifest, the API just sets
* the activity to be the default one to handle the given intent filter.
@@ -9745,18 +9831,22 @@
*
* <p>NOTE: Performs disk I/O and shouldn't be called on the main thread.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param filter The IntentFilter for which a default handler is added.
* @param activity The Activity that is added as default intent handler.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
@SupportsCoexistence
- public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter,
+ public void addPersistentPreferredActivity(@Nullable ComponentName admin, IntentFilter filter,
@NonNull ComponentName activity) {
throwIfParentInstance("addPersistentPreferredActivity");
if (mService != null) {
try {
- mService.addPersistentPreferredActivity(admin, filter, activity);
+ mService.addPersistentPreferredActivity(admin, mContext.getPackageName(), filter,
+ activity);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9764,22 +9854,30 @@
}
/**
- * Called by a profile owner or device owner to remove all persistent intent handler preferences
- * associated with the given package that were set by {@link #addPersistentPreferredActivity}.
+ * Called by a profile owner or device owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK} to remove all
+ * persistent intent handler preferences associated with the given package that were set by
+ * {@link #addPersistentPreferredActivity}.
* <p>
* The calling device admin must be a profile owner. If it is not, a security exception will be
* thrown.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The name of the package for which preferences are removed.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
*/
- public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
+ public void clearPackagePersistentPreferredActivities(@Nullable ComponentName admin,
String packageName) {
throwIfParentInstance("clearPackagePersistentPreferredActivities");
if (mService != null) {
try {
- mService.clearPackagePersistentPreferredActivities(admin, packageName);
+ mService.clearPackagePersistentPreferredActivities(
+ admin,
+ mContext.getPackageName(),
+ packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9788,27 +9886,69 @@
/**
* Must be called by a device owner or a profile owner of an organization-owned managed profile
- * to set the default SMS application.
+ * or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_DEFAULT_SMS} to set the default SMS
+ * application.
* <p>
* This method can be called on the {@link DevicePolicyManager} instance, returned by
* {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner
* of an organization-owned managed profile and the package must be a pre-installed system
* package. If called on the parent instance, then the default SMS application is set on the
* personal profile.
+ * <p>
+ * Starting from Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the profile
+ * owner of an organization-owned managed profile can also call this method directly (not on the
+ * parent profile instance) to set the default SMS application in the work profile. This is only
+ * meaningful when work profile telephony is enabled by {@link #setManagedSubscriptionsPolicy}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The name of the package to set as the default SMS application.
- * @throws SecurityException if {@code admin} is not a device or profile owner or if
- * called on the parent profile and the {@code admin} is not a
- * profile owner of an organization-owned managed profile.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or if
+ * called on the parent profile and the {@code admin} is not a
+ * profile owner of an organization-owned managed profile and
+ * if the caller has not been granted the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_DEFAULT_SMS}.
* @throws IllegalArgumentException if called on the parent profile and the package
* provided is not a pre-installed system package.
*/
- public void setDefaultSmsApplication(@NonNull ComponentName admin,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_DEFAULT_SMS, conditional = true)
+ public void setDefaultSmsApplication(@Nullable ComponentName admin,
@NonNull String packageName) {
if (mService != null) {
try {
- mService.setDefaultSmsApplication(admin, packageName, mParentInstance);
+ mService.setDefaultSmsApplication(admin, mContext.getPackageName(), packageName,
+ mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Must be called by a device owner or a profile owner of an organization-owned managed profile
+ * to set the default dialer application for the calling user.
+ * <p>
+ * When the profile owner of an organization-owned managed profile calls this method, it sets
+ * the default dialer application in the work profile. This is only meaningful when work profile
+ * telephony is enabled by {@link #setManagedSubscriptionsPolicy}.
+ * <p>
+ * If the device does not support telephony ({@link PackageManager#FEATURE_TELEPHONY}), calling
+ * this method will do nothing.
+ *
+ * @param packageName The name of the package to set as the default dialer application.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or a
+ * profile owner of an organization-owned managed profile.
+ * @throws IllegalArgumentException if the package cannot be set as the default dialer, for
+ * example if the package is not installed or does not expose
+ * the expected activities or services that a dialer app is
+ * required to have.
+ */
+ public void setDefaultDialerApplication(@NonNull String packageName) {
+ throwIfParentInstance("setDefaultDialerApplication");
+ if (mService != null) {
+ try {
+ mService.setDefaultDialerApplication(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9927,6 +10067,11 @@
* owner, and the application restrictions managing package via
* {@link #getApplicationRestrictions}.
*
+ * <p>Starting from Android Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+ * multiple admins can set app restrictions for the same application, the target application can
+ * get the list of app restrictions set by each admin via
+ * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin}.
+ *
* <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -10522,22 +10667,29 @@
}
/**
- * Called by the profile owner of a managed profile so that some intents sent in the managed
- * profile can also be resolved in the parent, or vice versa. Only activity intents are
- * supported.
+ * Called by the profile owner of a managed profile or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}. so that some
+ * intents sent in the managed profile can also be resolved in the parent, or vice versa.
+ * Only activity intents are supported.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param filter The {@link IntentFilter} the intent has to match to be also resolved in the
* other profile
* @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and
* {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner and is not a
+ * holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}.
*/
- public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional = true)
+ public void addCrossProfileIntentFilter(@Nullable ComponentName admin, IntentFilter filter,
+ int flags) {
throwIfParentInstance("addCrossProfileIntentFilter");
if (mService != null) {
try {
- mService.addCrossProfileIntentFilter(admin, filter, flags);
+ mService.addCrossProfileIntentFilter(admin, mContext.getPackageName(), filter,
+ flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -10545,9 +10697,10 @@
}
/**
- * Called by a profile owner of a managed profile to remove the cross-profile intent filters
- * that go from the managed profile to the parent, or from the parent to the managed profile.
- * Only removes those that have been set by the profile owner.
+ * Called by a profile owner of a managed profile or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION} to remove the
+ * cross-profile intent filters that go from the managed profile to the parent, or from the
+ * parent to the managed profile. Only removes those that have been set by the profile owner.
* <p>
* <em>Note</em>: A list of default cross profile intent filters are set up by the system when
* the profile is created, some of them ensure the proper functioning of the profile, while
@@ -10556,14 +10709,18 @@
* profile data sharing is not desired, they can be disabled with
* {@link UserManager#DISALLOW_SHARE_INTO_MANAGED_PROFILE}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @throws SecurityException if {@code admin} is not a profile owner.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
+ * @throws SecurityException if {@code admin} is not a profile owner and is not a
+ * holder of the permission
+ * @link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}.
*/
- public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional = true)
+ public void clearCrossProfileIntentFilters(@Nullable ComponentName admin) {
throwIfParentInstance("clearCrossProfileIntentFilters");
if (mService != null) {
try {
- mService.clearCrossProfileIntentFilters(admin);
+ mService.clearCrossProfileIntentFilters(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11352,9 +11509,11 @@
}
/**
- * Called by a profile or device owner to set a user restriction specified by the key.
+ * Called by a profile owner, device owner or a holder of any permission that is associated with
+ * a user restriction to set a user restriction specified by the key.
* <p>
- * The calling device admin must be a profile or device owner; if it is not, a security
+ * The calling device admin must be a profile owner, device owner or holder of any permission
+ * that is associated with a user restriction; if it is not, a security
* exception will be thrown.
* <p>
* The profile owner of an organization-owned managed profile may invoke this method on
@@ -11362,7 +11521,8 @@
* {@link #getParentProfileInstance(ComponentName)}, for enforcing device-wide restrictions.
* <p>
* See the constants in {@link android.os.UserManager} for the list of restrictions that can
- * be enforced device-wide.
+ * be enforced device-wide. These constants will also state in their documentation which
+ * permission is required to manage the restriction using this API.
*
* <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
* above, calling this API will result in applying the restriction locally on the calling user,
@@ -11373,7 +11533,8 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param key The key of the restriction.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner and if the caller
+ * has not been granted the permission to set the given user restriction.
*/
public void addUserRestriction(@NonNull ComponentName admin,
@UserManager.UserRestrictionKey String key) {
@@ -11388,21 +11549,24 @@
}
/**
- * Called by a profile or device owner to set a user restriction specified by the provided
- * {@code key} globally on all users. To clear the restriction use
- * {@link #clearUserRestriction}.
+ * Called by a profile owner, device owner or a holder of any permission that is associated with
+ * a user restriction to set a user restriction specified by the provided {@code key} globally
+ * on all users. To clear the restriction use {@link #clearUserRestriction}.
*
* <p>For a given user, a restriction will be set if it was applied globally or locally by any
* admin.
*
- * <p> The calling device admin must be a profile or device owner; if it is not, a security
+ * <p> The calling device admin must be a profile owner, device owner or or a holder of any
+ * permission that is associated with a user restriction; if it is not, a security
* exception will be thrown.
*
* <p> See the constants in {@link android.os.UserManager} for the list of restrictions that can
- * be enforced device-wide.
+ * be enforced device-wide. These constants will also state in their documentation which
+ * permission is required to manage the restriction using this API.
*
* @param key The key of the restriction.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner and if the
+ * caller has not been granted the permission to set the given user restriction.
* @throws IllegalStateException if caller is not targeting Android
* {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
*/
@@ -11418,7 +11582,8 @@
}
/**
- * Called by a profile or device owner to clear a user restriction specified by the key.
+ * Called by a profile owner, device owner or a holder of any permission that is associated with
+ * a user restriction to clear a user restriction specified by the key.
* <p>
* The calling device admin must be a profile or device owner; if it is not, a security
* exception will be thrown.
@@ -11427,7 +11592,9 @@
* the {@link DevicePolicyManager} instance it obtained from
* {@link #getParentProfileInstance(ComponentName)}, for clearing device-wide restrictions.
* <p>
- * See the constants in {@link android.os.UserManager} for the list of restrictions.
+ * See the constants in {@link android.os.UserManager} for the list of restrictions. These
+ * constants state in their documentation which permission is required to manage the restriction
+ * using this API.
*
* <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
* above, calling this API will result in clearing any local and global restriction with the
@@ -11435,7 +11602,8 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param key The key of the restriction.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner and if the
+ * caller has not been granted the permission to set the given user restriction.
*/
public void clearUserRestriction(@NonNull ComponentName admin,
@UserManager.UserRestrictionKey String key) {
@@ -11450,11 +11618,11 @@
}
/**
- * Called by a profile or device owner to get user restrictions set with
+ * Called by an admin to get user restrictions set by themselves with
* {@link #addUserRestriction(ComponentName, String)}.
* <p>
- * The target user may have more restrictions set by the system or other device owner / profile
- * owner. To get all the user restrictions currently set, use
+ * The target user may have more restrictions set by the system or other admin.
+ * To get all the user restrictions currently set, use
* {@link UserManager#getUserRestrictions()}.
* <p>
* The profile owner of an organization-owned managed profile may invoke this method on
@@ -11728,8 +11896,9 @@
}
/**
- * Called by a device owner or profile owner to disable account management for a specific type
- * of account.
+ * Called by a device owner, profile owner or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT}
+ * to disable account management for a specific type of account.
* <p>
* The calling device admin must be a device owner or profile owner. If it is not, a security
* exception will be thrown.
@@ -11746,18 +11915,22 @@
* organization-owned device, to restrict accounts that may not be managed on the primary
* profile.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param accountType For which account management is disabled or enabled.
* @param disabled The boolean indicating that account management will be disabled (true) or
* enabled (false).
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or has not been
+ * granted the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT}.
*/
- public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, conditional = true)
+ public void setAccountManagementDisabled(@Nullable ComponentName admin, String accountType,
boolean disabled) {
if (mService != null) {
try {
- mService.setAccountManagementDisabled(admin, accountType, disabled,
- mParentInstance);
+ mService.setAccountManagementDisabled(admin, mContext.getPackageName(), accountType,
+ disabled, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11787,8 +11960,13 @@
* @see #getAccountTypesWithManagementDisabled()
* Note that calling this method on the parent profile instance will return the same
* value as calling it on the main {@code DevicePolicyManager} instance.
+ *
+ * @throws SecurityException if the userId is different to the caller's and the caller has not
+ * been granted {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT} and
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}.
* @hide
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, conditional = true)
public @Nullable String[] getAccountTypesWithManagementDisabledAsUser(int userId) {
return getAccountTypesWithManagementDisabledAsUser(userId, false);
}
@@ -11801,7 +11979,8 @@
int userId, boolean parentInstance) {
if (mService != null) {
try {
- return mService.getAccountTypesWithManagementDisabledAsUser(userId, parentInstance);
+ return mService.getAccountTypesWithManagementDisabledAsUser(userId,
+ mContext.getPackageName(), parentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11869,26 +12048,31 @@
* package list results in locked tasks belonging to those packages to be finished.
* <p>
* This function can only be called by the device owner, a profile owner of an affiliated user
- * or profile, or the profile owner when no device owner is set. See {@link #isAffiliatedUser}.
+ * or profile, or the profile owner when no device owner is set or holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}. See
+ * {@link #isAffiliatedUser}.
* Any package set via this method will be cleared if the user becomes unaffiliated.
*
* @param packages The list of packages allowed to enter lock task mode
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
- * affiliated user or profile, or the profile owner when no device owner is set.
+ * affiliated user or profile, or the profile owner when no device owner is set or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
* @see #isAffiliatedUser
* @see Activity#startLockTask()
* @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
* @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
* @see UserManager#DISALLOW_CREATE_WINDOWS
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
@SupportsCoexistence
- public void setLockTaskPackages(@NonNull ComponentName admin, @NonNull String[] packages)
+ public void setLockTaskPackages(@Nullable ComponentName admin, @NonNull String[] packages)
throws SecurityException {
throwIfParentInstance("setLockTaskPackages");
if (mService != null) {
try {
- mService.setLockTaskPackages(admin, packages);
+ mService.setLockTaskPackages(admin, mContext.getPackageName(), packages);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11898,16 +12082,20 @@
/**
* Returns the list of packages allowed to start the lock task mode.
*
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
- * affiliated user or profile, or the profile owner when no device owner is set.
+ * affiliated user or profile, or the profile owner when no device owner is set or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
* @see #isAffiliatedUser
* @see #setLockTaskPackages
*/
- public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
+ public @NonNull String[] getLockTaskPackages(@Nullable ComponentName admin) {
throwIfParentInstance("getLockTaskPackages");
if (mService != null) {
try {
- return mService.getLockTaskPackages(admin);
+ return mService.getLockTaskPackages(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11941,22 +12129,26 @@
* {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}.
*
* <p>This method can only be called by the device owner, a profile owner of an affiliated
- * user or profile, or the profile owner when no device owner is set. See
+ * user or profile, or the profile owner when no device owner is set or holders of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}. See
* {@link #isAffiliatedUser}.
* Any features set using this method are cleared if the user becomes unaffiliated.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param flags The system features enabled during lock task mode.
* @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
- * affiliated user or profile, or the profile owner when no device owner is set.
+ * affiliated user or profile, or the profile owner when no device owner is set or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
* @see #isAffiliatedUser
**/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
@SupportsCoexistence
- public void setLockTaskFeatures(@NonNull ComponentName admin, @LockTaskFeature int flags) {
+ public void setLockTaskFeatures(@Nullable ComponentName admin, @LockTaskFeature int flags) {
throwIfParentInstance("setLockTaskFeatures");
if (mService != null) {
try {
- mService.setLockTaskFeatures(admin, flags);
+ mService.setLockTaskFeatures(admin, mContext.getPackageName(), flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11966,18 +12158,21 @@
/**
* Gets which system features are enabled for LockTask mode.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return bitfield of flags. See {@link #setLockTaskFeatures(ComponentName, int)} for a list.
* @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
- * affiliated user or profile, or the profile owner when no device owner is set.
+ * affiliated user or profile, or the profile owner when no device owner is set or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
* @see #isAffiliatedUser
* @see #setLockTaskFeatures
*/
- public @LockTaskFeature int getLockTaskFeatures(@NonNull ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
+ public @LockTaskFeature int getLockTaskFeatures(@Nullable ComponentName admin) {
throwIfParentInstance("getLockTaskFeatures");
if (mService != null) {
try {
- return mService.getLockTaskFeatures(admin);
+ return mService.getLockTaskFeatures(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -12259,7 +12454,8 @@
* {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false} will be
* returned.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param millis time in milliseconds since the Epoch
* @return {@code true} if set time succeeded, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not a device owner or a profile owner
@@ -12267,11 +12463,11 @@
* {@link android.Manifest.permission#SET_TIME}.
*/
@RequiresPermission(value = SET_TIME, conditional = true)
- public boolean setTime(@NonNull ComponentName admin, long millis) {
+ public boolean setTime(@Nullable ComponentName admin, long millis) {
throwIfParentInstance("setTime");
if (mService != null) {
try {
- return mService.setTime(admin, millis);
+ return mService.setTime(admin, mContext.getPackageName(), millis);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -12288,7 +12484,8 @@
* returned.
*
* @see android.app.AlarmManager#setTimeZone(String)
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param timeZone one of the Olson ids from the list returned by
* {@link java.util.TimeZone#getAvailableIDs}
* @return {@code true} if set timezone succeeded, {@code false} otherwise.
@@ -12297,11 +12494,11 @@
* {@link android.Manifest.permission#SET_TIME_ZONE}.
*/
@RequiresPermission(value = SET_TIME_ZONE, conditional = true)
- public boolean setTimeZone(@NonNull ComponentName admin, String timeZone) {
+ public boolean setTimeZone(@Nullable ComponentName admin, String timeZone) {
throwIfParentInstance("setTimeZone");
if (mService != null) {
try {
- return mService.setTimeZone(admin, timeZone);
+ return mService.setTimeZone(admin, mContext.getPackageName(), timeZone);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -12452,16 +12649,19 @@
/**
* Change whether a user can uninstall a package. This function can be called by a device owner,
* profile owner, or by a delegate given the {@link #DELEGATION_BLOCK_UNINSTALL} scope via
- * {@link #setDelegatedScopes}.
+ * {@link #setDelegatedScopes} or holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if the caller is a block uninstall delegate.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName package to change.
* @param uninstallBlocked true if the user shouldn't be able to uninstall the package.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL}.
* @see #setDelegatedScopes
* @see #DELEGATION_BLOCK_UNINSTALL
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional = true)
@SupportsCoexistence
public void setUninstallBlocked(@Nullable ComponentName admin, String packageName,
boolean uninstallBlocked) {
@@ -12490,17 +12690,21 @@
* <a href="/training/basics/intents/package-visibility">manage package visibility</a>.
*
* @param admin The name of the admin component whose blocking policy will be checked, or
- * {@code null} to check whether any admin has blocked the uninstallation.
+ * {@code null} to check whether any admin has blocked the uninstallation. Starting
+ * from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} admin will be
+ * ignored and assumed {@code null}.
* @param packageName package to check.
* @return true if uninstallation is blocked and the given package is visible to you, false
* otherwise if uninstallation isn't blocked or the given package isn't visible to you.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner. Starting
+ * from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} there will not be a security
+ * check at all.
*/
public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) {
throwIfParentInstance("isUninstallBlocked");
if (mService != null) {
try {
- return mService.isUninstallBlocked(admin, packageName);
+ return mService.isUninstallBlocked(packageName);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -12509,26 +12713,33 @@
}
/**
- * Called by the profile owner of a managed profile to enable widget providers from a given
- * package to be available in the parent profile. As a result the user will be able to add
- * widgets from the allowlisted package running under the profile to a widget host which runs
- * under the parent profile, for example the home screen. Note that a package may have zero or
- * more provider components, where each component provides a different widget type.
+ * Called by the profile owner of a managed profile or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION} to enable
+ * widget providers from a given package to be available in the parent profile. As a result the
+ * user will be able to add widgets from the allowlisted package running under the profile to a
+ * widget host which runs under the parent profile, for example the home screen. Note that a
+ * package may have zero or more provider components, where each component provides a different
+ * widget type.
* <p>
* <strong>Note:</strong> By default no widget provider package is allowlisted.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The package from which widget providers are allowlisted.
* @return Whether the package was added.
- * @throws SecurityException if {@code admin} is not a profile owner.
+ * @throws SecurityException if {@code admin} is not a profile owner and not a holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}.
* @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
* @see #getCrossProfileWidgetProviders(android.content.ComponentName)
*/
- public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional = true)
+ public boolean addCrossProfileWidgetProvider(@Nullable ComponentName admin,
+ String packageName) {
throwIfParentInstance("addCrossProfileWidgetProvider");
if (mService != null) {
try {
- return mService.addCrossProfileWidgetProvider(admin, packageName);
+ return mService.addCrossProfileWidgetProvider(admin,
+ mContext.getPackageName(), packageName);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -12537,26 +12748,31 @@
}
/**
- * Called by the profile owner of a managed profile to disable widget providers from a given
- * package to be available in the parent profile. For this method to take effect the package
- * should have been added via
+ * Called by the profile owner of a managed profile or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION} to disable
+ * widget providers from a given package to be available in the parent profile. For this method
+ * to take effect the package should have been added via
* {@link #addCrossProfileWidgetProvider( android.content.ComponentName, String)}.
* <p>
* <strong>Note:</strong> By default no widget provider package is allowlisted.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The package from which widget providers are no longer allowlisted.
* @return Whether the package was removed.
- * @throws SecurityException if {@code admin} is not a profile owner.
+ * @throws SecurityException if {@code admin} is not a profile owner and not a holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}.
* @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
* @see #getCrossProfileWidgetProviders(android.content.ComponentName)
*/
- public boolean removeCrossProfileWidgetProvider(
- @NonNull ComponentName admin, String packageName) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional = true)
+ public boolean removeCrossProfileWidgetProvider(@Nullable ComponentName admin,
+ String packageName) {
throwIfParentInstance("removeCrossProfileWidgetProvider");
if (mService != null) {
try {
- return mService.removeCrossProfileWidgetProvider(admin, packageName);
+ return mService.removeCrossProfileWidgetProvider(admin, mContext.getPackageName(),
+ packageName);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -12565,20 +12781,25 @@
}
/**
- * Called by the profile owner of a managed profile to query providers from which packages are
- * available in the parent profile.
+ * Called by the profile owner of a managed profile or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION} to query
+ * providers from which packages are available in the parent profile.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return The allowlisted package list.
* @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
* @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
- * @throws SecurityException if {@code admin} is not a profile owner.
+ * @throws SecurityException if {@code admin} is not a profile owner and not a holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}.
*/
- public @NonNull List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, conditional = true)
+ public @NonNull List<String> getCrossProfileWidgetProviders(@Nullable ComponentName admin) {
throwIfParentInstance("getCrossProfileWidgetProviders");
if (mService != null) {
try {
- List<String> providers = mService.getCrossProfileWidgetProviders(admin);
+ List<String> providers = mService.getCrossProfileWidgetProviders(admin,
+ mContext.getPackageName());
if (providers != null) {
return providers;
}
@@ -12714,9 +12935,10 @@
}
/**
- * Called by device owner or profile owner of secondary users that is affiliated with the
- * device to disable the status bar. Disabling the status bar blocks notifications and quick
- * settings.
+ * Called by device owner, profile owner of secondary users that is affiliated with the
+ * device or a holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_STATUS_BAR} to disable the status
+ * bar. Disabling the status bar blocks notifications and quick settings.
* <p>
* <strong>Note:</strong> This method has no effect for LockTask mode. The behavior of the
* status bar in LockTask mode can be configured with
@@ -12727,18 +12949,21 @@
* <p>This policy does not have any effect while on the lock screen, where the status bar will
* not be disabled. Using LockTask instead of this method is recommended.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param disabled {@code true} disables the status bar, {@code false} reenables it.
* @return {@code false} if attempting to disable the status bar failed. {@code true} otherwise.
- * @throws SecurityException if {@code admin} is not the device owner, or a profile owner of
- * secondary user that is affiliated with the device.
+ * @throws SecurityException if {@code admin} is not the device owner, a profile owner of
+ * secondary user that is affiliated with the device or if the caller is not a holder of
+ * the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_STATUS_BAR}.
* @see #isAffiliatedUser
* @see #getSecondaryUsers
*/
- public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_STATUS_BAR, conditional = true)
+ public boolean setStatusBarDisabled(@Nullable ComponentName admin, boolean disabled) {
throwIfParentInstance("setStatusBarDisabled");
try {
- return mService.setStatusBarDisabled(admin, disabled);
+ return mService.setStatusBarDisabled(admin, mContext.getPackageName(), disabled);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -12904,7 +13129,8 @@
* cannot manage it through the UI, and {@link #PERMISSION_GRANT_STATE_GRANTED granted} in which
* the permission is granted and the user cannot manage it through the UI. This method can only
* be called by a profile owner, device owner, or a delegate given the
- * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
+ * {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes} or holders of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS} .
* <p/>
* Note that user cannot manage other permissions in the affected group through the UI
* either and their granted state will be kept as the current value. Thus, it's recommended that
@@ -12967,22 +13193,25 @@
* the permissions listed above and {@code grantState} of
* {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them.
*
- * @param admin Which profile or device owner this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The application to grant or revoke a permission to.
* @param permission The permission to grant or revoke.
* @param grantState The permission grant state which is one of
* {@link #PERMISSION_GRANT_STATE_DENIED}, {@link #PERMISSION_GRANT_STATE_DEFAULT},
* {@link #PERMISSION_GRANT_STATE_GRANTED},
* @return whether the permission was successfully granted or revoked.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS}.
* @see #PERMISSION_GRANT_STATE_DENIED
* @see #PERMISSION_GRANT_STATE_DEFAULT
* @see #PERMISSION_GRANT_STATE_GRANTED
* @see #setDelegatedScopes
* @see #DELEGATION_PERMISSION_GRANT
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, conditional = true)
@SupportsCoexistence
- public boolean setPermissionGrantState(@NonNull ComponentName admin,
+ public boolean setPermissionGrantState(@Nullable ComponentName admin,
@NonNull String packageName, @NonNull String permission,
@PermissionGrantState int grantState) {
throwIfParentInstance("setPermissionGrantState");
@@ -13010,11 +13239,11 @@
* function can be called by a device owner, profile owner, or by a delegate given the
* {@link #DELEGATION_PERMISSION_GRANT} scope via {@link #setDelegatedScopes}.
*
- * @param admin Which profile or device owner this request is associated with, or {@code null}
- * if the caller is a permission grant delegate.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packageName The application to check the grant state for.
* @param permission The permission to check for.
- * @return the current grant state specified by device policy. If the profile or device owner
+ * @return the current grant state specified by device policy. If admins have not set a grant
* has not set a grant state, the return value is
* {@link #PERMISSION_GRANT_STATE_DEFAULT}. This does not indicate whether or not the
* permission is currently granted for the package.
@@ -13023,12 +13252,14 @@
* be one of {@link #PERMISSION_GRANT_STATE_DENIED} or
* {@link #PERMISSION_GRANT_STATE_GRANTED}, which indicates if the permission is
* currently denied or granted.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS}.
* @see #setPermissionGrantState(ComponentName, String, String, int)
* @see PackageManager#checkPermission(String, String)
* @see #setDelegatedScopes
* @see #DELEGATION_PERMISSION_GRANT
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, conditional = true)
public @PermissionGrantState int getPermissionGrantState(@Nullable ComponentName admin,
@NonNull String packageName, @NonNull String permission) {
throwIfParentInstance("getPermissionGrantState");
@@ -13143,7 +13374,9 @@
}
/**
- * Called by a device admin to set the short support message. This will be displayed to the user
+ * Called by a device admin or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE} to set the short
+ * support message. This will be displayed to the user
* in settings screens where funtionality has been disabled by the admin. The message should be
* limited to a short statement such as "This setting is disabled by your administrator. Contact
* someone@example.com for support." If the message is longer than 200 characters it may be
@@ -13154,17 +13387,21 @@
* and set a new version of this string accordingly.
*
* @see #setLongSupportMessage
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param message Short message to be displayed to the user in settings or null to clear the
* existing message.
- * @throws SecurityException if {@code admin} is not an active administrator.
+ * @throws SecurityException if {@code admin} is not an active administrator and is not a
+ * holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE}.
*/
- public void setShortSupportMessage(@NonNull ComponentName admin,
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, conditional = true)
+ public void setShortSupportMessage(@Nullable ComponentName admin,
@Nullable CharSequence message) {
throwIfParentInstance("setShortSupportMessage");
if (mService != null) {
try {
- mService.setShortSupportMessage(admin, message);
+ mService.setShortSupportMessage(admin, mContext.getPackageName(), message);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13172,18 +13409,23 @@
}
/**
- * Called by a device admin to get the short support message.
+ * Called by a device admin or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE} to get the short
+ * support message.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)} or
* null if no message has been set.
- * @throws SecurityException if {@code admin} is not an active administrator.
+ * @throws SecurityException if {@code admin} is not an active administrator and not a holder of
+ * the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE}..
*/
- public CharSequence getShortSupportMessage(@NonNull ComponentName admin) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, conditional = true)
+ public CharSequence getShortSupportMessage(@Nullable ComponentName admin) {
throwIfParentInstance("getShortSupportMessage");
if (mService != null) {
try {
- return mService.getShortSupportMessage(admin);
+ return mService.getShortSupportMessage(admin, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13709,51 +13951,47 @@
}
/**
- * Called by the device owner (since API 26) or profile owner (since API 24) or, starting from
- * Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
- * holders of the permission
- * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY} to set the
- * name of the organization under management.
+ * Called by the device owner (since API 26) or profile owner (since API 24) or holders of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY} to
+ * set the name of the organization under management.
*
* <p>If the organization name needs to be localized, it is the responsibility of the caller
* to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast and set a new version of this
* string accordingly.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with or can be
- * {@code null} if accessing with a permission without association with a DeviceAdminReceiver.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param title The organization name or {@code null} to clear a previously set name.
* @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
* permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY}.
*/
- @RequiresPermission(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY)
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, conditional = true)
public void setOrganizationName(@Nullable ComponentName admin, @Nullable CharSequence title) {
throwIfParentInstance("setOrganizationName");
try {
- mService.setOrganizationName(admin, title);
+ mService.setOrganizationName(admin, mContext.getPackageName(), title);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
- * Called by the device owner (since API 26) or profile owner (since API 24) or, starting from
- * Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
- * holders of the permission
- * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY
+ * Called by the device owner (since API 26) or profile owner (since API 24) or holders of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY
* to retrieve the name of the organization under management.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with or can be
- * {@code null} if accessing with a permission without association with a DeviceAdminReceiver.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return The organization name or {@code null} if none is set.
* @throws SecurityException if {@code admin} if {@code admin} is not a device or profile
* owner or holder of the
* permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY}.
*/
- @RequiresPermission(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY)
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, conditional = true)
public @Nullable CharSequence getOrganizationName(@Nullable ComponentName admin) {
throwIfParentInstance("getOrganizationName");
try {
- return mService.getOrganizationName(admin);
+ return mService.getOrganizationName(admin, mContext.getPackageName());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -15552,22 +15790,28 @@
}
/**
- * Called by a device owner or a profile owner to disable user control over apps. User will not
- * be able to clear app data or force-stop packages. When called by a device owner, applies to
- * all users on the device. Starting from Android 13, packages with user control disabled are
- * exempted from being put in the "restricted" App Standby Bucket.
+ * Called by a device owner or a profile owner or holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL} to disable user
+ * control over apps. User will not be able to clear app data or force-stop packages. When
+ * called by a device owner, applies to all users on the device. Starting from Android 13,
+ * packages with user control disabled are exempted from being put in the "restricted" App
+ * Standby Bucket.
*
- * @param admin which {@link DeviceAdminReceiver} this request is associated with
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param packages The package names for the apps.
- * @throws SecurityException if {@code admin} is not a device owner or a profile owner.
+ * @throws SecurityException if {@code admin} is not a device owner or a profile owner or
+ * holder of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL}.
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional = true)
@SupportsCoexistence
- public void setUserControlDisabledPackages(@NonNull ComponentName admin,
+ public void setUserControlDisabledPackages(@Nullable ComponentName admin,
@NonNull List<String> packages) {
throwIfParentInstance("setUserControlDisabledPackages");
if (mService != null) {
try {
- mService.setUserControlDisabledPackages(admin, packages);
+ mService.setUserControlDisabledPackages(admin, mContext.getPackageName(), packages);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -15576,17 +15820,21 @@
/**
* Returns the list of packages over which user control is disabled by a device or profile
- * owner.
+ * owner or holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL}.
*
- * @param admin which {@link DeviceAdminReceiver} this request is associated with
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
+ * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APPS_CONTROL}.
*/
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_APPS_CONTROL, conditional = true)
@NonNull
- public List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
+ public List<String> getUserControlDisabledPackages(@Nullable ComponentName admin) {
throwIfParentInstance("getUserControlDisabledPackages");
if (mService != null) {
try {
- return mService.getUserControlDisabledPackages(admin);
+ return mService.getUserControlDisabledPackages(admin, mContext.getPackageName());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -15595,7 +15843,9 @@
}
/**
- * Called by device owner or profile owner of an organization-owned managed profile to toggle
+ * Called by device owner or profile owner of an organization-owned managed profile or
+ * holders of the permission
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE} to toggle
* Common Criteria mode for the device. When the device is in Common Criteria mode,
* certain device functionalities are tuned to meet the higher
* security level required by Common Criteria certification. For example:
@@ -15608,14 +15858,16 @@
* <p><em>Note:</em> if Common Critera mode is turned off after being enabled previously,
* all existing WiFi configurations will be lost.
*
- * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @param enabled whether Common Criteria mode should be enabled or not.
*/
- public void setCommonCriteriaModeEnabled(@NonNull ComponentName admin, boolean enabled) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE, conditional = true)
+ public void setCommonCriteriaModeEnabled(@Nullable ComponentName admin, boolean enabled) {
throwIfParentInstance("setCommonCriteriaModeEnabled");
if (mService != null) {
try {
- mService.setCommonCriteriaModeEnabled(admin, enabled);
+ mService.setCommonCriteriaModeEnabled(admin, mContext.getPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15629,8 +15881,8 @@
* aggregated device-wide Common Criteria mode state by passing {@code null} as the
* {@code admin} argument.
*
- * @param admin which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if the caller is not a device admin.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
* @return {@code true} if Common Criteria mode is enabled, {@code false} otherwise.
*/
public boolean isCommonCriteriaModeEnabled(@Nullable ComponentName admin) {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index eefadea..5345947 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -25,7 +25,6 @@
import android.os.UserHandle;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -279,11 +278,13 @@
* The given permission will be checked along with its associated cross-user permission, if it
* exists and the target user is different to the calling user.
*
+ * @param callerPackage the package of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException If the calling process has not been granted the permission.
*/
- public abstract void enforcePermission(String permission, int targetUserId);
+ public abstract void enforcePermission(String callerPackage, String permission,
+ int targetUserId);
/**
* Return whether the calling process has been granted permission to apply a device policy on
@@ -292,10 +293,12 @@
* The given permission will be checked along with its associated cross-user
* permission, if it exists and the target user is different to the calling user.
*
+ * @param callerPackage the package of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
*/
- public abstract boolean hasPermission(String permission, int targetUserId);
+ public abstract boolean hasPermission(String callerPackage, String permission,
+ int targetUserId);
/**
* Returns whether new "turn off work" behavior is enabled via feature flag.
@@ -318,8 +321,9 @@
public abstract boolean isApplicationExemptionsFlagEnabled();
/**
- * Returns the application restrictions set by each admin for the given {@code packageName}.
+ * Returns a map of admin to {@link Bundle} map of restrictions set by the admins for the
+ * provided {@code packageName} in the provided {@code userId}
*/
- public abstract Map<String, Bundle> getApplicationRestrictionsPerAdmin(
- String packageName, int userId);
+ public abstract List<Bundle> getApplicationRestrictionsPerAdminForUser(
+ String packageName, @UserIdInt int userId);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 14c6ecd..a4dedea 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -124,7 +124,7 @@
/**
* @param factoryReset only applicable when `targetSdk >= U`, either tries to factoryReset/fail or removeUser/fail otherwise
**/
- void wipeDataWithReason(int flags, String wipeReasonForUser, boolean parent, boolean factoryReset);
+ void wipeDataWithReason(String callerPackageName, int flags, String wipeReasonForUser, boolean parent, boolean factoryReset);
void setFactoryResetProtectionPolicy(in ComponentName who, String callerPackageName, in FactoryResetProtectionPolicy policy);
FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(in ComponentName who);
@@ -143,7 +143,7 @@
boolean requestBugreport(in ComponentName who);
void setCameraDisabled(in ComponentName who, String callerPackageName, boolean disabled, boolean parent);
- boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent);
+ boolean getCameraDisabled(in ComponentName who, String callerPackageName, int userHandle, boolean parent);
void setScreenCaptureDisabled(
in ComponentName who, String callerPackageName, boolean disabled, boolean parent);
@@ -235,10 +235,11 @@
boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle);
List<String> getAlwaysOnVpnLockdownAllowlist(in ComponentName who);
- void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
- void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
+ void addPersistentPreferredActivity(in ComponentName admin, String callerPackageName, in IntentFilter filter, in ComponentName activity);
+ void clearPackagePersistentPreferredActivities(in ComponentName admin, String callerPackageName, String packageName);
- void setDefaultSmsApplication(in ComponentName admin, String packageName, boolean parent);
+ void setDefaultSmsApplication(in ComponentName admin, String callerPackageName, String packageName, boolean parent);
+ void setDefaultDialerApplication(String packageName);
void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName);
@@ -254,8 +255,8 @@
Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
Bundle getUserRestrictionsGlobally(in String callerPackage);
- void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
- void clearCrossProfileIntentFilters(in ComponentName admin);
+ void addCrossProfileIntentFilter(in ComponentName admin, String callerPackageName, in IntentFilter filter, int flags);
+ void clearCrossProfileIntentFilters(in ComponentName admin, String callerPackageName);
boolean setPermittedAccessibilityServices(in ComponentName admin,in List<String> packageList);
List<String> getPermittedAccessibilityServices(in ComponentName admin);
@@ -292,9 +293,9 @@
int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
boolean installExistingPackage(in ComponentName admin, in String callerPackage, in String packageName);
- void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled, in boolean parent);
- String[] getAccountTypesWithManagementDisabled();
- String[] getAccountTypesWithManagementDisabledAsUser(int userId, in boolean parent);
+ void setAccountManagementDisabled(in ComponentName who, String callerPackageName, in String accountType, in boolean disabled, in boolean parent);
+ String[] getAccountTypesWithManagementDisabled(String callerPackageName);
+ String[] getAccountTypesWithManagementDisabledAsUser(int userId, String callerPackageName, in boolean parent);
void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
@@ -303,12 +304,12 @@
in List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs);
List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
- void setLockTaskPackages(in ComponentName who, in String[] packages);
- String[] getLockTaskPackages(in ComponentName who);
+ void setLockTaskPackages(in ComponentName who, String callerPackageName, in String[] packages);
+ String[] getLockTaskPackages(in ComponentName who, String callerPackageName);
boolean isLockTaskPermitted(in String pkg);
- void setLockTaskFeatures(in ComponentName who, int flags);
- int getLockTaskFeatures(in ComponentName who);
+ void setLockTaskFeatures(in ComponentName who, String callerPackageName, int flags);
+ int getLockTaskFeatures(in ComponentName who, String callerPackageName);
void setGlobalSetting(in ComponentName who, in String setting, in String value);
void setSystemSetting(in ComponentName who, in String setting, in String value);
@@ -319,8 +320,8 @@
void setLocationEnabled(in ComponentName who, boolean locationEnabled);
- boolean setTime(in ComponentName who, long millis);
- boolean setTimeZone(in ComponentName who, String timeZone);
+ boolean setTime(in ComponentName who, String callerPackageName, long millis);
+ boolean setTimeZone(in ComponentName who, String callerPackageName, String timeZone);
void setMasterVolumeMuted(in ComponentName admin, boolean on);
boolean isMasterVolumeMuted(in ComponentName admin);
@@ -328,7 +329,7 @@
void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userId);
void setUninstallBlocked(in ComponentName admin, in String callerPackage, in String packageName, boolean uninstallBlocked);
- boolean isUninstallBlocked(in ComponentName admin, in String packageName);
+ boolean isUninstallBlocked(in String packageName);
void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
boolean getCrossProfileCallerIdDisabled(in ComponentName who);
@@ -358,18 +359,18 @@
List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
in ComponentName agent, int userId, boolean parent);
- boolean addCrossProfileWidgetProvider(in ComponentName admin, String packageName);
- boolean removeCrossProfileWidgetProvider(in ComponentName admin, String packageName);
- List<String> getCrossProfileWidgetProviders(in ComponentName admin);
+ boolean addCrossProfileWidgetProvider(in ComponentName admin, String callerPackageName, String packageName);
+ boolean removeCrossProfileWidgetProvider(in ComponentName admin, String callerPackageName, String packageName);
+ List<String> getCrossProfileWidgetProviders(in ComponentName admin, String callerPackageName);
void setAutoTimeRequired(in ComponentName who, boolean required);
boolean getAutoTimeRequired();
- void setAutoTimeEnabled(in ComponentName who, boolean enabled);
- boolean getAutoTimeEnabled(in ComponentName who);
+ void setAutoTimeEnabled(in ComponentName who, String callerPackageName, boolean enabled);
+ boolean getAutoTimeEnabled(in ComponentName who, String callerPackageName);
- void setAutoTimeZoneEnabled(in ComponentName who, boolean enabled);
- boolean getAutoTimeZoneEnabled(in ComponentName who);
+ void setAutoTimeZoneEnabled(in ComponentName who, String callerPackageName, boolean enabled);
+ boolean getAutoTimeZoneEnabled(in ComponentName who, String callerPackageName);
void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
boolean getForceEphemeralUsers(in ComponentName who);
@@ -383,7 +384,7 @@
void clearSystemUpdatePolicyFreezePeriodRecord();
boolean setKeyguardDisabled(in ComponentName admin, boolean disabled);
- boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
+ boolean setStatusBarDisabled(in ComponentName who, String callerPackageName, boolean disabled);
boolean isStatusBarDisabled(in String callerPackage);
boolean getDoNotAskCredentialsOnBoot();
@@ -403,8 +404,8 @@
String getWifiMacAddress(in ComponentName admin, String callerPackageName);
void reboot(in ComponentName admin);
- void setShortSupportMessage(in ComponentName admin, in CharSequence message);
- CharSequence getShortSupportMessage(in ComponentName admin);
+ void setShortSupportMessage(in ComponentName admin, String callerPackageName, in CharSequence message);
+ CharSequence getShortSupportMessage(in ComponentName admin, String callerPackageName);
void setLongSupportMessage(in ComponentName admin, in CharSequence message);
CharSequence getLongSupportMessage(in ComponentName admin);
@@ -417,8 +418,8 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
- void setOrganizationName(in ComponentName admin, in CharSequence title);
- CharSequence getOrganizationName(in ComponentName admin);
+ void setOrganizationName(in ComponentName admin, String callerPackageName, in CharSequence title);
+ CharSequence getOrganizationName(in ComponentName admin, String callerPackageName);
CharSequence getDeviceOwnerOrganizationName();
CharSequence getOrganizationNameForUser(int userHandle);
@@ -463,10 +464,10 @@
long getLastBugReportRequestTime();
long getLastNetworkLogRetrievalTime();
- boolean setResetPasswordToken(in ComponentName admin, in byte[] token);
- boolean clearResetPasswordToken(in ComponentName admin);
- boolean isResetPasswordTokenActive(in ComponentName admin);
- boolean resetPasswordWithToken(in ComponentName admin, String password, in byte[] token, int flags);
+ boolean setResetPasswordToken(in ComponentName admin, String callerPackageName, in byte[] token);
+ boolean clearResetPasswordToken(in ComponentName admin, String callerPackageName);
+ boolean isResetPasswordTokenActive(in ComponentName admin, String callerPackageName);
+ boolean resetPasswordWithToken(in ComponentName admin, String callerPackageName, String password, in byte[] token, int flags);
boolean isCurrentInputMethodSetByOwner();
StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
@@ -527,11 +528,11 @@
boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant);
boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias);
- void setUserControlDisabledPackages(in ComponentName admin, in List<String> packages);
+ void setUserControlDisabledPackages(in ComponentName admin, String callerPackageName, in List<String> packages);
- List<String> getUserControlDisabledPackages(in ComponentName admin);
+ List<String> getUserControlDisabledPackages(in ComponentName admin, String callerPackageName);
- void setCommonCriteriaModeEnabled(in ComponentName admin, boolean enabled);
+ void setCommonCriteriaModeEnabled(in ComponentName admin, String callerPackageName, boolean enabled);
boolean isCommonCriteriaModeEnabled(in ComponentName admin);
int getPersonalAppsSuspendedReasons(in ComponentName admin);
diff --git a/core/java/android/app/admin/PolicyUpdateReceiver.java b/core/java/android/app/admin/PolicyUpdateReceiver.java
index 58f4f1b..b5d9286 100644
--- a/core/java/android/app/admin/PolicyUpdateReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdateReceiver.java
@@ -19,6 +19,7 @@
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
+import android.annotation.TestApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -112,31 +113,37 @@
"android.app.admin.extra.ACCOUNT_TYPE";
/**
+ * String extra containing the policy identifier.
+ *
* @hide
*/
- public static final String EXTRA_POLICY_CHANGED_KEY =
- "android.app.admin.extra.POLICY_CHANGED_KEY";
-
- /**
- * @hide
- */
+ @TestApi
public static final String EXTRA_POLICY_KEY = "android.app.admin.extra.POLICY_KEY";
/**
+ * Bundle extra containing additional information related to a policy.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_BUNDLE_KEY =
"android.app.admin.extra.POLICY_BUNDLE_KEY";
/**
+ * Int extra containing the {@link PolicyUpdateResult} code.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_UPDATE_RESULT_KEY =
"android.app.admin.extra.POLICY_UPDATE_RESULT_KEY";
/**
+ * Int extra containing the target user this policy update applies to.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_TARGET_USER_ID =
"android.app.admin.extra.POLICY_TARGET_USER_ID";
diff --git a/core/java/android/app/admin/TargetUser.java b/core/java/android/app/admin/TargetUser.java
index ed4fae0..ce6f32b 100644
--- a/core/java/android/app/admin/TargetUser.java
+++ b/core/java/android/app/admin/TargetUser.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import java.util.Objects;
@@ -29,23 +30,35 @@
*/
public final class TargetUser {
/**
+ * Indicates that the policy relates to the user the admin is installed on.
+ *
* @hide
*/
+ @TestApi
public static final int LOCAL_USER_ID = -1;
/**
+ * For admins of profiles, this indicates that the policy relates to the parent profile.
+ *
* @hide
*/
+ @TestApi
public static final int PARENT_USER_ID = -2;
/**
+ * This indicates the policy is a global policy.
+ *
* @hide
*/
+ @TestApi
public static final int GLOBAL_USER_ID = -3;
/**
+ * Indicates that the policy relates to some unknown user on the device.
+ *
* @hide
*/
+ @TestApi
public static final int UNKNOWN_USER_ID = -3;
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0d330ce..fcffc6f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7384,7 +7384,6 @@
* @throws IllegalArgumentException if the given device ID is not a valid ID of the default
* device or a virtual device.
*
- * @see #isDeviceContext()
* @see #createDeviceContext(int)
* @hide
*/
@@ -7408,26 +7407,8 @@
* </p>
*
* <p>
- * This method will only return a reliable value for this instance if
- * {@link Context#isDeviceContext()} is {@code true}. The system can assign an arbitrary device
- * id value for Contexts not logically associated with a device.
- * </p>
- *
- * @return the ID of the device this context is associated with.
- * @see #isDeviceContext()
- * @see #createDeviceContext(int)
- * @see #registerDeviceIdChangeListener(Executor, IntConsumer)
- */
- public int getDeviceId() {
- throw new RuntimeException("Not implemented. Must override in a subclass.");
- }
-
- /**
- * Indicates whether the value of {@link Context#getDeviceId()} can be relied upon for
- * this instance. It will return {@code true} for Contexts created by
- * {@link Context#createDeviceContext(int)} which reference a valid device ID, as well as for
- * UI and Display Contexts.
- * <p>
+ * This method will only return a reliable value for this instance if it was created with
+ * {@link Context#createDeviceContext(int)}, or if this instance is a UI or Display Context.
* Contexts created with {@link Context#createDeviceContext(int)} will have an explicit
* device association, which will never change, even if the underlying device is closed or is
* removed. UI Contexts and Display Contexts are
@@ -7437,15 +7418,12 @@
* logically associated with a device.
* </p>
*
- * @return {@code true} if {@link Context#getDeviceId()} is reliable, {@code false} otherwise.
- *
+ * @return the ID of the device this context is associated with.
* @see #createDeviceContext(int)
- * @see #getDeviceId()}
- * @see #createDisplayContext(Display)
+ * @see #registerDeviceIdChangeListener(Executor, IntConsumer)
* @see #isUiContext()
*/
-
- public boolean isDeviceContext() {
+ public int getDeviceId() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -7464,7 +7442,6 @@
* @param listener The listener {@code IntConsumer} to call which will receive the updated
* device ID.
*
- * @see Context#isDeviceContext()
* @see Context#getDeviceId()
* @see Context#createDeviceContext(int)
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a103128..91be664 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1201,11 +1201,6 @@
}
@Override
- public boolean isDeviceContext() {
- return mBase.isDeviceContext();
- }
-
- @Override
public void registerDeviceIdChangeListener(@NonNull @CallbackExecutor Executor executor,
@NonNull IntConsumer listener) {
mBase.registerDeviceIdChangeListener(executor, listener);
diff --git a/core/java/android/content/IRestrictionsManager.aidl b/core/java/android/content/IRestrictionsManager.aidl
index db9146f..0fcd63f 100644
--- a/core/java/android/content/IRestrictionsManager.aidl
+++ b/core/java/android/content/IRestrictionsManager.aidl
@@ -26,6 +26,7 @@
*/
interface IRestrictionsManager {
Bundle getApplicationRestrictions(in String packageName);
+ List<Bundle> getApplicationRestrictionsPerAdminForUser(int userId, in String packageName);
boolean hasRestrictionsProvider();
void requestPermission(in String packageName, in String requestType, in String requestId,
in PersistableBundle requestData);
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index ffd80ea..8115292 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -18,7 +18,10 @@
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
+import android.annotation.NonNull;
import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
+import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -31,6 +34,7 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.os.UserManager;
import android.service.restrictions.RestrictionsReceiver;
import android.util.AttributeSet;
import android.util.Log;
@@ -422,6 +426,14 @@
* to this application.
* @return the application restrictions as a Bundle. Returns null if there
* are no restrictions.
+ *
+ * @deprecated Use {@link #getApplicationRestrictionsPerAdmin} instead.
+ * Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it is
+ * possible for there to be multiple managing agents on the device with the ability to set
+ * restrictions. This API will only to return the restrictions set by device policy controllers
+ * (DPCs)
+ *
+ * @see DevicePolicyManager
*/
public Bundle getApplicationRestrictions() {
try {
@@ -435,6 +447,46 @@
}
/**
+ * Returns a {@link List} containing a {@link Bundle} for each managing agent that has set
+ * restrictions for the current application, the bundle contains any application restrictions
+ * set for the current package. The order of the items in the list is not guaranteed to remain
+ * stable between multiple calls.
+ *
+ * <p>Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+ * it is possible for there to be multiple managing agents on the device with the ability to set
+ * restrictions, e.g. an Enterprise DPC and a Supervision admin.
+ *
+ * <p>Each {@link Bundle} consists of key-value pairs, as defined by the application,
+ * where the types of values may be:
+ * <ul>
+ * <li>{@code boolean}
+ * <li>{@code int}
+ * <li>{@code String} or {@code String[]}
+ * <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]}
+ * </ul>
+ *
+ * <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread
+ *
+ * @return a {@link List} of {@link Bundle} containing the restrictions set by admins for that
+ * package. Returns an empty {@link List} if there are no saved restrictions.
+ *
+ * @see UserManager#KEY_RESTRICTIONS_PENDING
+ */
+ @WorkerThread
+ @UserHandleAware
+ public @NonNull List<Bundle> getApplicationRestrictionsPerAdmin() {
+ try {
+ if (mService != null) {
+ return mService.getApplicationRestrictionsPerAdminForUser(
+ mContext.getUserId(), mContext.getPackageName());
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ return null;
+ }
+
+ /**
* Called by an application to check if there is an active Restrictions Provider. If
* there isn't, {@link #requestPermission(String, String, PersistableBundle)} is not available.
*
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index cfd291f..2b4ea70 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2914,10 +2914,10 @@
* <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
* <li>The app being installed targets:
* <ul>
- * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
- * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
- * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher after
- * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
+ * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on
+ * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
+ * <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b>
+ * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
* </ul>
* </li>
* <li>The installer is:
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 07473d2..ff7fc36 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -332,6 +332,7 @@
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<Void, ClearCredentialStateException> callback) {
+ requireNonNull(request, "request must not be null");
requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null");
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 3b62881..80ae8a8 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -86,6 +86,12 @@
boolean isExemptFromLowPowerStandby();
boolean isReasonAllowedInLowPowerStandby(int reason);
boolean isFeatureAllowedInLowPowerStandby(String feature);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)")
+ void acquireLowPowerStandbyPorts(in IBinder token, in List<LowPowerStandbyPortDescription> ports);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)")
+ void releaseLowPowerStandbyPorts(in IBinder token);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
+ List<LowPowerStandbyPortDescription> getActiveLowPowerStandbyPorts();
parcelable LowPowerStandbyPolicy {
String identifier;
@@ -94,6 +100,13 @@
List<String> allowedFeatures;
}
+ parcelable LowPowerStandbyPortDescription {
+ int protocol;
+ int portMatcher;
+ int portNumber;
+ @nullable String bindAddress;
+ }
+
@UnsupportedAppUsage
void reboot(boolean confirm, String reason, boolean wait);
void rebootSafeMode(boolean confirm, boolean wait);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 797730b..3cf3ea2 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -133,6 +133,7 @@
boolean isUserForeground(int userId);
boolean isUserVisible(int userId);
int[] getVisibleUsers();
+ int getDisplayIdAssignedToUser();
boolean isUserNameSet(int userId);
boolean hasRestrictedProfiles(int userId);
boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 03c32d70..ed1afa2 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -32,6 +32,7 @@
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.net.LinkAddress;
import android.service.dreams.Sandman;
import android.sysprop.InitProperties;
import android.util.ArrayMap;
@@ -47,6 +48,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -2472,6 +2474,49 @@
}
/**
+ * Creates a new Low Power Standby ports lock.
+ *
+ * <p>A Low Power Standby ports lock requests that the given ports remain open during
+ * Low Power Standby.
+ * Call {@link LowPowerStandbyPortsLock#acquire} to acquire the lock.
+ * This request is only respected if the calling package is exempt
+ * (see {@link #isExemptFromLowPowerStandby()}), and until the returned
+ * {@code LowPowerStandbyPorts} object is destroyed or has
+ * {@link LowPowerStandbyPortsLock#release} called on it.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)
+ @NonNull
+ public LowPowerStandbyPortsLock newLowPowerStandbyPortsLock(
+ @NonNull List<LowPowerStandbyPortDescription> ports) {
+ LowPowerStandbyPortsLock standbyPorts = new LowPowerStandbyPortsLock(ports);
+ return standbyPorts;
+ }
+
+ /**
+ * Gets all ports that should remain open in standby.
+ * Only includes ports requested by exempt packages (see {@link #getLowPowerStandbyPolicy()}).
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_LOW_POWER_STANDBY,
+ android.Manifest.permission.DEVICE_POWER
+ })
+ @NonNull
+ public List<LowPowerStandbyPortDescription> getActiveLowPowerStandbyPorts() {
+ try {
+ return LowPowerStandbyPortDescription.fromParcelable(
+ mService.getActiveLowPowerStandbyPorts());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return whether the given application package name is on the device's power allowlist.
* Apps can be placed on the allowlist through the settings UI invoked by
* {@link android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}.
@@ -2980,6 +3025,19 @@
"android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
/**
+ * Intent that is broadcast when Low Power Standby exempt ports change.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @see #getActiveLowPowerStandbyPorts
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY)
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LOW_POWER_STANDBY_PORTS_CHANGED =
+ "android.os.action.LOW_POWER_STANDBY_PORTS_CHANGED";
+
+ /**
* Signals that wake-on-lan/wake-on-wlan is allowed in Low Power Standby.
*
* <p>If Low Power Standby is enabled ({@link #isLowPowerStandbyEnabled()}),
@@ -3154,6 +3212,322 @@
}
/**
+ * Describes ports that may be requested to remain open during Low Power Standby.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class LowPowerStandbyPortDescription {
+ /** @hide */
+ @IntDef(prefix = { "PROTOCOL_" }, value = {
+ PROTOCOL_TCP,
+ PROTOCOL_UDP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Protocol {
+ }
+
+ /**
+ * Constant to indicate the {@link LowPowerStandbyPortDescription} refers to a TCP port.
+ */
+ public static final int PROTOCOL_TCP = 1;
+ /**
+ * Constant to indicate the {@link LowPowerStandbyPortDescription} refers to a UDP port.
+ */
+ public static final int PROTOCOL_UDP = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "MATCH_PORT_" }, value = {
+ MATCH_PORT_LOCAL,
+ MATCH_PORT_REMOTE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PortMatcher {
+ }
+ /**
+ * Constant to indicate the {@link LowPowerStandbyPortDescription}'s port number is to be
+ * matched against the socket's local port number (the destination port number of an
+ * incoming packet).
+ */
+ public static final int MATCH_PORT_LOCAL = 1;
+ /**
+ * Constant to indicate the {@link LowPowerStandbyPortDescription}'s port number is to be
+ * matched against the socket's remote port number (the source port number of an
+ * incoming packet).
+ */
+ public static final int MATCH_PORT_REMOTE = 2;
+
+ @Protocol
+ private final int mProtocol;
+ @PortMatcher
+ private final int mPortMatcher;
+ private final int mPortNumber;
+ @Nullable
+ private final LinkAddress mBindAddress;
+
+ /**
+ * Describes a port.
+ *
+ * @param protocol The protocol of the port to match, {@link #PROTOCOL_TCP} or
+ * {@link #PROTOCOL_UDP}.
+ * @param portMatcher Whether to match the source port number of an incoming packet
+ * ({@link #MATCH_PORT_REMOTE}), or the destination port
+ * ({@link #MATCH_PORT_LOCAL}).
+ * @param portNumber The port number to match.
+ *
+ * @see #newLowPowerStandbyPortsLock(List)
+ */
+ public LowPowerStandbyPortDescription(@Protocol int protocol, @PortMatcher int portMatcher,
+ int portNumber) {
+ this.mProtocol = protocol;
+ this.mPortMatcher = portMatcher;
+ this.mPortNumber = portNumber;
+ this.mBindAddress = null;
+ }
+
+ /**
+ * Describes a port.
+ *
+ * @param protocol The protocol of the port to match, {@link #PROTOCOL_TCP} or
+ * {@link #PROTOCOL_UDP}.
+ * @param portMatcher Whether to match the source port number of an incoming packet
+ * ({@link #MATCH_PORT_REMOTE}), or the destination port
+ * ({@link #MATCH_PORT_LOCAL}).
+ * @param portNumber The port number to match.
+ * @param bindAddress The bind address to match.
+ *
+ * @see #newLowPowerStandbyPortsLock(List)
+ */
+ public LowPowerStandbyPortDescription(@Protocol int protocol, @PortMatcher int portMatcher,
+ int portNumber, @Nullable LinkAddress bindAddress) {
+ this.mProtocol = protocol;
+ this.mPortMatcher = portMatcher;
+ this.mPortNumber = portNumber;
+ this.mBindAddress = bindAddress;
+ }
+
+ private String protocolToString(int protocol) {
+ switch (protocol) {
+ case PROTOCOL_TCP: return "TCP";
+ case PROTOCOL_UDP: return "UDP";
+ }
+ return String.valueOf(protocol);
+ }
+
+ private String portMatcherToString(int portMatcher) {
+ switch (portMatcher) {
+ case MATCH_PORT_LOCAL: return "MATCH_PORT_LOCAL";
+ case MATCH_PORT_REMOTE: return "MATCH_PORT_REMOTE";
+ }
+ return String.valueOf(portMatcher);
+ }
+
+ /**
+ * Returns the described port's protocol,
+ * either {@link #PROTOCOL_TCP} or {@link #PROTOCOL_UDP}.
+ *
+ * @see #PROTOCOL_TCP
+ * @see #PROTOCOL_UDP
+ * @see #getPortNumber()
+ * @see #getPortMatcher()
+ */
+ @Protocol
+ public int getProtocol() {
+ return mProtocol;
+ }
+
+ /**
+ * Returns how the port number ({@link #getPortNumber()}) should be matched against
+ * incoming packets.
+ * Either {@link #PROTOCOL_TCP} or {@link #PROTOCOL_UDP}.
+ *
+ * @see #PROTOCOL_TCP
+ * @see #PROTOCOL_UDP
+ * @see #getPortNumber()
+ * @see #getProtocol()
+ */
+ @PortMatcher
+ public int getPortMatcher() {
+ return mPortMatcher;
+ }
+
+ /**
+ * Returns how the port number that incoming packets should be matched against.
+ *
+ * @see #getPortMatcher()
+ * @see #getProtocol()
+ */
+ public int getPortNumber() {
+ return mPortNumber;
+ }
+
+ /**
+ * Returns the bind address to match against, or {@code null} if matching against any
+ * bind address.
+ *
+ * @see #getPortMatcher()
+ * @see #getProtocol()
+ */
+ @Nullable
+ public LinkAddress getBindAddress() {
+ return mBindAddress;
+ }
+
+ @Override
+ public String toString() {
+ return "PortDescription{"
+ + "mProtocol=" + protocolToString(mProtocol)
+ + ", mPortMatcher=" + portMatcherToString(mPortMatcher)
+ + ", mPortNumber=" + mPortNumber
+ + ", mBindAddress=" + mBindAddress
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof LowPowerStandbyPortDescription)) return false;
+ LowPowerStandbyPortDescription that = (LowPowerStandbyPortDescription) o;
+ return mProtocol == that.mProtocol && mPortMatcher == that.mPortMatcher
+ && mPortNumber == that.mPortNumber && Objects.equals(mBindAddress,
+ that.mBindAddress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mProtocol, mPortMatcher, mPortNumber, mBindAddress);
+ }
+
+ /** @hide */
+ public static IPowerManager.LowPowerStandbyPortDescription toParcelable(
+ LowPowerStandbyPortDescription portDescription) {
+ if (portDescription == null) {
+ return null;
+ }
+
+ IPowerManager.LowPowerStandbyPortDescription parcelablePortDescription =
+ new IPowerManager.LowPowerStandbyPortDescription();
+ parcelablePortDescription.protocol = portDescription.mProtocol;
+ parcelablePortDescription.portMatcher = portDescription.mPortMatcher;
+ parcelablePortDescription.portNumber = portDescription.mPortNumber;
+ if (portDescription.mBindAddress != null) {
+ parcelablePortDescription.bindAddress = portDescription.mBindAddress.toString();
+ }
+ return parcelablePortDescription;
+ }
+
+ /** @hide */
+ public static List<IPowerManager.LowPowerStandbyPortDescription> toParcelable(
+ List<LowPowerStandbyPortDescription> portDescriptions) {
+ if (portDescriptions == null) {
+ return null;
+ }
+
+ ArrayList<IPowerManager.LowPowerStandbyPortDescription> result = new ArrayList<>();
+ for (LowPowerStandbyPortDescription port : portDescriptions) {
+ result.add(toParcelable(port));
+ }
+ return result;
+ }
+
+ /** @hide */
+ public static LowPowerStandbyPortDescription fromParcelable(
+ IPowerManager.LowPowerStandbyPortDescription parcelablePortDescription) {
+ if (parcelablePortDescription == null) {
+ return null;
+ }
+
+ LinkAddress bindAddress = null;
+ if (parcelablePortDescription.bindAddress != null) {
+ bindAddress = new LinkAddress(parcelablePortDescription.bindAddress);
+ }
+ return new LowPowerStandbyPortDescription(
+ parcelablePortDescription.protocol,
+ parcelablePortDescription.portMatcher,
+ parcelablePortDescription.portNumber,
+ bindAddress);
+ }
+
+ /** @hide */
+ public static List<LowPowerStandbyPortDescription> fromParcelable(
+ List<IPowerManager.LowPowerStandbyPortDescription> portDescriptions) {
+ if (portDescriptions == null) {
+ return null;
+ }
+
+ ArrayList<LowPowerStandbyPortDescription> result = new ArrayList<>();
+ for (IPowerManager.LowPowerStandbyPortDescription port : portDescriptions) {
+ result.add(fromParcelable(port));
+ }
+ return result;
+ }
+ }
+
+ /**
+ * An object that can be used to request network ports to remain open during Low Power Standby.
+ *
+ * <p>Use {@link #newLowPowerStandbyPortsLock} to create a ports lock, and {@link #acquire()}
+ * to request the ports to remain open. The request is only respected if the app requesting the
+ * lock is exempt from Low Power Standby ({@link #isExemptFromLowPowerStandby()}).
+ *
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("NotCloseable")
+ public final class LowPowerStandbyPortsLock {
+ private final IBinder mToken;
+ private final List<LowPowerStandbyPortDescription> mPorts;
+ private boolean mHeld;
+
+ LowPowerStandbyPortsLock(List<LowPowerStandbyPortDescription> ports) {
+ mPorts = ports;
+ mToken = new Binder();
+ }
+
+ /** Request the ports to remain open during standby. */
+ @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)
+ public void acquire() {
+ synchronized (mToken) {
+ try {
+ mService.acquireLowPowerStandbyPorts(mToken,
+ LowPowerStandbyPortDescription.toParcelable(mPorts));
+ mHeld = true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Release the request, allowing these ports to be blocked during standby.
+ *
+ * <p>Note: This lock is not reference counted, so calling this method will release the lock
+ * regardless of how many times {@link #acquire()} has been called before.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)
+ public void release() {
+ synchronized (mToken) {
+ try {
+ mService.releaseLowPowerStandbyPorts(mToken);
+ mHeld = false;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ synchronized (mToken) {
+ if (mHeld) {
+ Log.wtf(TAG, "LowPowerStandbyPorts finalized while still held");
+ release();
+ }
+ }
+ }
+ }
+
+ /**
* Constant for PreIdleTimeout normal mode (default mode, not short nor extend timeout) .
* @hide
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c60f558..9c55ad6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3052,6 +3052,19 @@
}
/**
+ * See {@link com.android.server.pm.UserManagerInternal#getDisplayAssignedToUser(int)}.
+ *
+ * @hide
+ */
+ public int getDisplayIdAssignedToUser() {
+ try {
+ return mService.getDisplayIdAssignedToUser();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return whether the context user is running in an "unlocked" state.
* <p>
* On devices with direct boot, a user is unlocked only after they've
@@ -5574,7 +5587,17 @@
* if there are no saved restrictions.
*
* @see #KEY_RESTRICTIONS_PENDING
+ *
+ * @deprecated Use
+ * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead.
+ * Starting from Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it is
+ * possible for there to be multiple managing agents on the device with the ability to set
+ * restrictions. This API will only to return the restrictions set by device policy controllers
+ * (DPCs)
+ *
+ * @see DevicePolicyManager
*/
+ @Deprecated
@WorkerThread
@UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU)
public Bundle getApplicationRestrictions(String packageName) {
@@ -5587,8 +5610,12 @@
}
/**
+ * @deprecated Use
+ * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead.
+ *
* @hide
*/
+ @Deprecated
@WorkerThread
public Bundle getApplicationRestrictions(String packageName, UserHandle user) {
try {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 19e759ca..947248a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10323,7 +10323,7 @@
/**
* If active unlock triggers on unlock intents, then also request active unlock on
- * these wake-up reasons. See PowerManager.WakeReason for value mappings.
+ * these wake-up reasons. See {@link PowerManager.WakeReason} for value mappings.
* WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this
* setting should be disabled, then this should be set to an empty string. A null value
* will use the system default value (WAKE_REASON_UNFOLD_DEVICE).
@@ -10333,6 +10333,17 @@
"active_unlock_wakeups_considered_unlock_intents";
/**
+ * If active unlock triggers and succeeds on these wakeups, force dismiss keyguard on
+ * these wake reasons. See {@link PowerManager#WakeReason} for value mappings.
+ * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this
+ * setting should be disabled, then this should be set to an empty string. A null value
+ * will use the system default value (WAKE_REASON_UNFOLD_DEVICE).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD =
+ "active_unlock_wakeups_to_force_dismiss_keyguard";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
@@ -18592,6 +18603,40 @@
* @hide
*/
public static final int ACCESSIBILITY_VIBRATION_WATCH_SPEED_VERY_FAST = 4;
+
+ /**
+ * The key to indicate the data migration status on device upgrade in Wear Services.
+ * @hide
+ */
+ public static final String UPGRADE_DATA_MIGRATION_STATUS =
+ "upgrade_data_migration_status";
+
+ /**
+ * Constant indicating that the data migration is not needed.
+ *
+ * The value should be provided with setting name {@link
+ * #UPGRADE_DATA_MIGRATION_STATUS}.
+ * @hide
+ */
+ public static final int UPGRADE_DATA_MIGRATION_NOT_NEEDED = 0;
+
+ /**
+ * Constant indicating that the data migration is not yet finished.
+ *
+ * The value should be provided with setting name {@link
+ * #UPGRADE_DATA_MIGRATION_STATUS}.
+ * @hide
+ */
+ public static final int UPGRADE_DATA_MIGRATION_PENDING = 1;
+
+ /**
+ * Constant indicating that the data migration is finished.
+ *
+ * The value should be provided with setting name {@link
+ * #UPGRADE_DATA_MIGRATION_STATUS}.
+ * @hide
+ */
+ public static final int UPGRADE_DATA_MIGRATION_DONE = 2;
}
}
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index b6c13c4..7e98bc7 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -107,6 +107,7 @@
}
private CredentialEntry(@NonNull Parcel in) {
+ requireNonNull(in, "parcel must not be null");
mType = in.readString8();
mSlice = in.readTypedObject(Slice.CREATOR);
mBeginGetCredentialOption = in.readTypedObject(BeginGetCredentialOption.CREATOR);
diff --git a/core/java/android/service/credentials/CredentialProviderInfo.java b/core/java/android/service/credentials/CredentialProviderInfo.java
index 75ba525..b5464db 100644
--- a/core/java/android/service/credentials/CredentialProviderInfo.java
+++ b/core/java/android/service/credentials/CredentialProviderInfo.java
@@ -16,6 +16,8 @@
package android.service.credentials;
+import static java.util.Objects.requireNonNull;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -112,10 +114,9 @@
"Provider is not a valid system provider: " + serviceInfo);
}
}
-
mIsSystemProvider = isSystemProvider;
- mContext = context;
- mServiceInfo = serviceInfo;
+ mContext = requireNonNull(context, "context must not be null");
+ mServiceInfo = requireNonNull(serviceInfo, "serviceInfo must not be null");
mCapabilities = new ArrayList<>();
mIcon = mServiceInfo.loadIcon(mContext.getPackageManager());
mLabel =
@@ -300,6 +301,7 @@
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests) {
+ requireNonNull(context, "context must not be null");
final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
for (ServiceInfo si :
getAvailableSystemServiceInfos(
@@ -381,6 +383,8 @@
int userId,
boolean disableSystemAppVerificationForTests,
int providerFilter) {
+ requireNonNull(context, "context must not be null");
+
// Get the device policy.
PackagePolicy pp = getDeviceManagerPolicy(context);
diff --git a/core/java/android/service/credentials/GetCredentialRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java
index 7cdccc6..4f13922 100644
--- a/core/java/android/service/credentials/GetCredentialRequest.java
+++ b/core/java/android/service/credentials/GetCredentialRequest.java
@@ -23,6 +23,8 @@
import com.android.internal.util.AnnotationValidations;
+import java.util.Objects;
+
/**
* Request for getting user's credential from a given credential provider.
*
@@ -43,8 +45,10 @@
public GetCredentialRequest(@NonNull CallingAppInfo callingAppInfo,
@NonNull CredentialOption credentialOption) {
- this.mCallingAppInfo = callingAppInfo;
- this.mCredentialOption = credentialOption;
+ this.mCallingAppInfo = Objects.requireNonNull(callingAppInfo,
+ "callingAppInfo must not be null");
+ this.mCredentialOption = Objects.requireNonNull(credentialOption,
+ "credentialOption must not be null");
}
private GetCredentialRequest(@NonNull Parcel in) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 00161c0..d21e5df 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -60,7 +60,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -180,8 +179,6 @@
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
- private Handler mBackgroundHandler;
- private HandlerThread mBackgroundThread;
static final class WallpaperCommand {
String action;
@@ -201,6 +198,14 @@
*/
public class Engine {
IWallpaperEngineWrapper mIWallpaperEngine;
+ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
+ final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
+
+ // 2D matrix [x][y] to represent a page of a portion of a window
+ EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
+ Bitmap mLastScreenshot;
+ int mLastWindowPage = -1;
+ private boolean mResetWindowPages;
// Copies from mIWallpaperEngine.
HandlerCaller mCaller;
@@ -261,27 +266,11 @@
final Object mLock = new Object();
boolean mOffsetMessageEnqueued;
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
float mPendingXOffset;
float mPendingYOffset;
float mPendingXOffsetStep;
float mPendingYOffsetStep;
-
- /**
- * local color extraction related fields
- * to be used by the background thread only (except the atomic boolean)
- */
- final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
- final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
- private long mLastProcessLocalColorsTimestamp;
- private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
- private int mPixelCopyCount = 0;
- // 2D matrix [x][y] to represent a page of a portion of a window
- EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
- Bitmap mLastScreenshot;
- private boolean mResetWindowPages;
-
boolean mPendingSync;
MotionEvent mPendingMove;
boolean mIsInAmbientMode;
@@ -290,8 +279,12 @@
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
+ // used to throttle processLocalColors
+ private long mLastProcessLocalColorsTimestamp;
+ private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
private final Supplier<Long> mClockFunction;
private final Handler mHandler;
+
private Display mDisplay;
private Context mDisplayContext;
private int mDisplayState;
@@ -861,7 +854,7 @@
+ "was not established.");
}
mResetWindowPages = true;
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} catch (RemoteException e) {
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
}
@@ -1399,7 +1392,7 @@
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
@@ -1543,7 +1536,7 @@
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (mReportedVisible) processLocalColors();
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} else {
AnimationHandler.requestAnimatorsEnabled(visible, this);
}
@@ -1627,44 +1620,31 @@
}
// setup local color extraction data
- processLocalColors();
+ processLocalColors(xOffset, xOffsetStep);
}
/**
* Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
* {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
*/
- private void processLocalColors() {
+ private void processLocalColors(float xOffset, float xOffsetStep) {
if (mProcessLocalColorsPending.compareAndSet(false, true)) {
final long now = mClockFunction.get();
final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
final long timeToWait = Math.max(0,
PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess);
- mBackgroundHandler.postDelayed(() -> {
+ mHandler.postDelayed(() -> {
mLastProcessLocalColorsTimestamp = now + timeToWait;
mProcessLocalColorsPending.set(false);
- processLocalColorsInternal();
+ processLocalColorsInternal(xOffset, xOffsetStep);
}, timeToWait);
}
}
- private void processLocalColorsInternal() {
+ private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
// implemented by the wallpaper
if (supportsLocalColorExtraction()) return;
- if (!mBackgroundHandler.getLooper().isCurrentThread()) {
- throw new IllegalStateException(
- "ProcessLocalColors should be called from the background thread");
- }
- float xOffset;
- float xOffsetStep;
- float wallpaperDimAmount;
- synchronized (mLock) {
- xOffset = mPendingXOffset;
- xOffsetStep = mPendingXOffsetStep;
- wallpaperDimAmount = mWallpaperDimAmount;
- }
-
if (DEBUG) {
Log.d(TAG, "processLocalColors " + xOffset + " of step "
+ xOffsetStep);
@@ -1727,7 +1707,7 @@
xPage = mWindowPages.length - 1;
}
current = mWindowPages[xPage];
- updatePage(current, xPage, xPages, wallpaperDimAmount);
+ updatePage(current, xPage, xPages, finalXOffsetStep);
Trace.endSection();
}
@@ -1747,21 +1727,16 @@
}
}
- /**
- * Must be called with the surface lock held.
- * Must not be called if the surface is not valid.
- * Will unlock the surface when done using it.
- */
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
- float wallpaperDimAmount) {
-
+ float xOffsetStep) {
// in case the clock is zero, we start with negative time
long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
-
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
+ return;
+ }
Surface surface = mSurfaceHolder.getSurface();
if (!surface.isValid()) return;
boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1777,41 +1752,32 @@
Bitmap screenShot = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
final Bitmap finalScreenShot = screenShot;
- final String pixelCopySectionName = "WallpaperService#pixelCopy";
- final int pixelCopyCount = mPixelCopyCount++;
- Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
- try {
- PixelCopy.request(surface, screenShot, (res) -> {
- mSurfaceHolder.mSurfaceLock.unlock();
- Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
- if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
- if (res != PixelCopy.SUCCESS) {
- Bitmap lastBitmap = currentPage.getBitmap();
- // assign the last bitmap taken for now
- currentPage.setBitmap(mLastScreenshot);
- Bitmap lastScreenshot = mLastScreenshot;
- if (lastScreenshot != null && !lastScreenshot.isRecycled()
- && !Objects.equals(lastBitmap, lastScreenshot)) {
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
- }
- } else {
- mLastScreenshot = finalScreenShot;
- // going to hold this lock for a while
- currentPage.setBitmap(finalScreenShot);
- currentPage.setLastUpdateTime(current);
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
+ Trace.beginSection("WallpaperService#pixelCopy");
+ PixelCopy.request(surface, screenShot, (res) -> {
+ Trace.endSection();
+ if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
+ if (res != PixelCopy.SUCCESS) {
+ Bitmap lastBitmap = currentPage.getBitmap();
+ // assign the last bitmap taken for now
+ currentPage.setBitmap(mLastScreenshot);
+ Bitmap lastScreenshot = mLastScreenshot;
+ if (lastScreenshot != null && !lastScreenshot.isRecycled()
+ && !Objects.equals(lastBitmap, lastScreenshot)) {
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
}
- }, mBackgroundHandler);
- } catch (IllegalArgumentException e) {
- // this can potentially happen if the surface is invalidated right between the
- // surface.isValid() check and the PixelCopy operation.
- // in this case, stop: we'll compute colors on the next processLocalColors call.
- Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
- }
+ } else {
+ mLastScreenshot = finalScreenShot;
+ // going to hold this lock for a while
+ currentPage.setBitmap(finalScreenShot);
+ currentPage.setLastUpdateTime(current);
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
+ }
+ }, mHandler);
+
}
// locked by the passed page
- private void updatePageColors(
- EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) {
+ private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
+ float xOffsetStep) {
if (page.getBitmap() == null) return;
Trace.beginSection("WallpaperService#updatePageColors");
if (DEBUG) {
@@ -1834,7 +1800,7 @@
Log.e(TAG, "Error creating page local color bitmap", e);
continue;
}
- WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
+ WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
target.recycle();
WallpaperColors currentColor = page.getColors(area);
@@ -1851,14 +1817,12 @@
+ " local color callback for area" + area + " for page " + pageIndx
+ " of " + numPages);
}
- mHandler.post(() -> {
- try {
- mConnection.onLocalWallpaperColorsChanged(area, color,
- mDisplayContext.getDisplayId());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
- }
- });
+ try {
+ mConnection.onLocalWallpaperColorsChanged(area, color,
+ mDisplayContext.getDisplayId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+ }
}
}
Trace.endSection();
@@ -1888,6 +1852,7 @@
if (supportsLocalColorExtraction()) return;
if (!mResetWindowPages) return;
mResetWindowPages = false;
+ mLastWindowPage = -1;
for (int i = 0; i < mWindowPages.length; i++) {
mWindowPages[i].setLastUpdateTime(0L);
}
@@ -1913,10 +1878,12 @@
if (DEBUG) {
Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
}
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
mLocalColorsToAdd.addAll(regions);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingYOffset);
});
+
+
}
/**
@@ -1926,7 +1893,7 @@
*/
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
if (supportsLocalColorExtraction()) return;
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
float step = mPendingXOffsetStep;
mLocalColorsToAdd.removeAll(regions);
mLocalColorAreas.removeAll(regions);
@@ -2583,10 +2550,6 @@
@Override
public void onCreate() {
Trace.beginSection("WPMS.onCreate");
- final String localColorExtractorThreadName = "DefaultWallpaperLocalColorExtractor";
- mBackgroundThread = new HandlerThread(localColorExtractorThreadName);
- mBackgroundThread.start();
- mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
super.onCreate();
Trace.endSection();
}
@@ -2599,7 +2562,6 @@
mActiveEngines.get(i).detach();
}
mActiveEngines.clear();
- mBackgroundThread.quitSafely();
Trace.endSection();
}
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
index f7e459e..b924f35 100644
--- a/core/java/android/speech/IRecognitionListener.aidl
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -96,6 +96,16 @@
void onEndOfSegmentedSession();
/**
+ * Called when the language detection (and switching) results are available.
+ *
+ * @param results a Bundle containing the identifiers of the most confidently detected language,
+ * the confidence level of the detection,
+ * the alternative locales for the most confidently detected language,
+ * and the results of the language switching.
+ */
+ void onLanguageDetection(in Bundle results);
+
+ /**
* Reserved for adding future events.
*
* @param eventType the type of the occurred event
diff --git a/core/java/android/speech/RecognitionListener.java b/core/java/android/speech/RecognitionListener.java
index ee4a7d0..609f54e 100644
--- a/core/java/android/speech/RecognitionListener.java
+++ b/core/java/android/speech/RecognitionListener.java
@@ -117,6 +117,36 @@
default void onEndOfSegmentedSession() {}
/**
+ * Called when the language detection (and switching) results are available. This callback
+ * can be invoked on any number of occasions at any time between {@link #onBeginningOfSpeech()}
+ * and {@link #onEndOfSpeech()}, depending on the speech recognition service implementation.
+ *
+ * <p> To request language detection,
+ * use {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_DETECTION}.
+ * <p> To request automatic language switching,
+ * use {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_SWITCH}.
+ *
+ * @param results the returned language detection (and switching) results.
+ * <p> To retrieve the most confidently detected language IETF tag
+ * (as defined by BCP 47, e.g., "en-US", "de-DE"),
+ * use {@link Bundle#getString(String)}
+ * with {@link SpeechRecognizer#DETECTED_LANGUAGE} as the parameter.
+ * <p> To retrieve the language detection confidence level represented by a value
+ * prefixed by {@code LANGUAGE_DETECTION_CONFIDENCE_LEVEL_} and
+ * defined in {@link SpeechRecognizer}, use {@link Bundle#getInt(String)}
+ * with {@link SpeechRecognizer#LANGUAGE_DETECTION_CONFIDENCE_LEVEL} as the parameter.
+ * <p> To retrieve the alternative locales for the same language
+ * retrieved by the key {@link SpeechRecognizer#DETECTED_LANGUAGE},
+ * use {@link Bundle#getStringArrayList(String)}
+ * with {@link SpeechRecognizer#TOP_LOCALE_ALTERNATIVES} as the parameter.
+ * <p> To retrieve the language switching results represented by a value
+ * prefixed by {@code LANGUAGE_SWITCH_RESULT_} and defined in {@link SpeechRecognizer},
+ * use {@link Bundle#getInt(String)}
+ * with {@link SpeechRecognizer#LANGUAGE_SWITCH_RESULT} as the parameter.
+ */
+ default void onLanguageDetection(@NonNull Bundle results) {}
+
+ /**
* Reserved for adding future events.
*
* @param eventType the type of the occurred event
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index d1d80a4..4ecec8f 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -651,6 +651,39 @@
}
/**
+ * The service should call this method when the language detection (and switching)
+ * results are available. This method can be called on any number of occasions
+ * at any time between {@link #beginningOfSpeech()} and {@link #endOfSpeech()},
+ * depending on the speech recognition service implementation.
+ *
+ * @param results the returned language detection (and switching) results.
+ * <p> To retrieve the most confidently detected language IETF tag
+ * (as defined by BCP 47, e.g., "en-US", "de-DE"),
+ * use {@link Bundle#getString(String)}
+ * with {@link SpeechRecognizer#DETECTED_LANGUAGE} as the parameter.
+ * <p> To retrieve the language detection confidence level represented by a value
+ * prefixed by {@code LANGUAGE_DETECTION_CONFIDENCE_LEVEL_} defined in
+ * {@link SpeechRecognizer}, use {@link Bundle#getInt(String)} with
+ * {@link SpeechRecognizer#LANGUAGE_DETECTION_CONFIDENCE_LEVEL} as the parameter.
+ * <p> To retrieve the alternative locales for the same language
+ * retrieved by the key {@link SpeechRecognizer#DETECTED_LANGUAGE},
+ * use {@link Bundle#getStringArrayList(String)}
+ * with {@link SpeechRecognizer#TOP_LOCALE_ALTERNATIVES} as the parameter.
+ * <p> To retrieve the language switching results represented by a value
+ * prefixed by {@code LANGUAGE_SWITCH_RESULT_}
+ * and defined in {@link SpeechRecognizer}, use {@link Bundle#getInt(String)}
+ * with {@link SpeechRecognizer#LANGUAGE_SWITCH_RESULT} as the parameter.
+ */
+ @SuppressLint("CallbackMethodName") // For consistency with existing methods.
+ public void languageDetection(@NonNull Bundle results) {
+ try {
+ mListener.onLanguageDetection(results);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the Linux uid assigned to the process that sent you the current transaction that
* is being processed. This is obtained from {@link Binder#getCallingUid()}.
*/
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 7127fa1..118d028 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -572,4 +572,85 @@
*/
public static final String EXTRA_REQUEST_WORD_CONFIDENCE =
"android.speech.extra.REQUEST_WORD_CONFIDENCE";
+
+ /**
+ * Optional boolean indicating whether to enable language detection. When enabled, the
+ * recognizer will consistently identify the language of the current spoken utterance and
+ * provide that info via {@link RecognitionListener#onLanguageDetection(Bundle)}.
+ *
+ * <p> Depending on the recognizer implementation, this flag may have no effect.
+ */
+ public static final String EXTRA_ENABLE_LANGUAGE_DETECTION =
+ "android.speech.extra.ENABLE_LANGUAGE_DETECTION";
+
+ /**
+ * Optional list of IETF language tags (as defined by BCP 47, e.g. "en-US", "de-DE").
+ * This extra is to be used with {@link #EXTRA_ENABLE_LANGUAGE_DETECTION}.
+ * If set, the recognizer will constrain the language detection output
+ * to this list of languages, potentially improving detection accuracy.
+ */
+ public static final String EXTRA_LANGUAGE_DETECTION_ALLOWED_LANGUAGES =
+ "android.speech.extra.LANGUAGE_DETECTION_ALLOWED_LANGUAGES";
+
+ /**
+ * Optional string to enable automatic switching to the language being spoken with
+ * the desired sensitivity level, instead of being restricted to a single language.
+ * The corresponding language models must be downloaded to support the switch.
+ * Otherwise, the recognizer will report an error on a switch failure. The recognizer
+ * provides the switch results via {@link RecognitionListener#onLanguageDetection(Bundle)}.
+ *
+ * <p> Since detection is a necessary requirement for the language switching,
+ * setting this value implicitly enables {@link #EXTRA_ENABLE_LANGUAGE_DETECTION}.
+ *
+ * <p> Depending on the recognizer implementation, this value may have no effect.
+ *
+ * @see #LANGUAGE_SWITCH_HIGH_PRECISION
+ * @see #LANGUAGE_SWITCH_BALANCED
+ * @see #LANGUAGE_SWITCH_QUICK_RESPONSE
+ */
+ public static final String EXTRA_ENABLE_LANGUAGE_SWITCH =
+ "android.speech.extra.ENABLE_LANGUAGE_SWITCH";
+
+ /**
+ * A value to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}.
+ *
+ * <p> Enables language switch only when a new language is detected as
+ * {@link SpeechRecognizer#LANGUAGE_DETECTION_CONFIDENCE_LEVEL_HIGHLY_CONFIDENT},
+ * which means the service may wait for longer before switching.
+ *
+ * @see #EXTRA_ENABLE_LANGUAGE_SWITCH
+ */
+ public static final String LANGUAGE_SWITCH_HIGH_PRECISION = "high_precision";
+
+ /**
+ * A value to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}.
+ *
+ * <p> Enables language switch only when a new language is detected as at least
+ * {@link SpeechRecognizer#LANGUAGE_DETECTION_CONFIDENCE_LEVEL_CONFIDENT}, which means
+ * the service is balancing between detecting a new language confidently and switching early.
+ *
+ * @see #EXTRA_ENABLE_LANGUAGE_SWITCH
+ */
+ public static final String LANGUAGE_SWITCH_BALANCED = "balanced";
+
+ /**
+ * A value to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}.
+ *
+ * <p> Enables language switch only when a new language is detected as at least
+ * {@link SpeechRecognizer#LANGUAGE_DETECTION_CONFIDENCE_LEVEL_NOT_CONFIDENT},
+ * which means the service should switch at the earliest moment possible.
+ *
+ * @see #EXTRA_ENABLE_LANGUAGE_SWITCH
+ */
+ public static final String LANGUAGE_SWITCH_QUICK_RESPONSE = "quick_response";
+
+ /**
+ * Optional list of IETF language tags (as defined by BCP 47, e.g. "en-US", "de-DE"). This extra
+ * is to be used with {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}. If set, the recognizer will apply
+ * the auto switch only to these languages, even if the speech models of other languages also
+ * exist. The corresponding language models must be downloaded to support the switch.
+ * Otherwise, the recognizer will report an error on a switch failure.
+ */
+ public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES =
+ "android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES";
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index dce72f5..76eb09e 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -80,7 +80,7 @@
* recognition results, where the first element is the most likely candidate.
*/
public static final String RESULTS_RECOGNITION = "results_recognition";
-
+
/**
* Key used to retrieve a float array from the {@link Bundle} passed to the
* {@link RecognitionListener#onResults(Bundle)} and
@@ -124,6 +124,101 @@
public static final String RECOGNITION_PARTS = "recognition_parts";
/**
+ * Key used to retrieve a {@link String} representation of the IETF language tag (as defined by
+ * BCP 47, e.g., "en-US", "de-DE") of the detected language of the most recent audio chunk.
+ *
+ * <p> This info is returned to the client in the {@link Bundle} passed to
+ * {@link RecognitionListener#onLanguageDetection(Bundle)} only if
+ * {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_DETECTION} is set. Additionally, if
+ * {@link RecognizerIntent#EXTRA_LANGUAGE_DETECTION_ALLOWED_LANGUAGES} are listed,
+ * the detected language is constrained to be one from the list.
+ */
+ public static final String DETECTED_LANGUAGE = "detected_language";
+
+ /**
+ * Key used to retrieve the level of confidence of the detected language
+ * of the most recent audio chunk,
+ * represented by an {@code int} value prefixed by {@code LANGUAGE_DETECTION_CONFIDENCE_LEVEL_}.
+ *
+ * <p> This info is returned to the client in the {@link Bundle} passed to
+ * {@link RecognitionListener#onLanguageDetection(Bundle)} only if
+ * {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_DETECTION} is set.
+ */
+ public static final String LANGUAGE_DETECTION_CONFIDENCE_LEVEL =
+ "language_detection_confidence_level";
+
+ /**
+ * The level of language detection confidence.
+ *
+ * @hide
+ */
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"LANGUAGE_DETECTION_CONFIDENCE_LEVEL_"}, value = {
+ LANGUAGE_DETECTION_CONFIDENCE_LEVEL_UNKNOWN,
+ LANGUAGE_DETECTION_CONFIDENCE_LEVEL_NOT_CONFIDENT,
+ LANGUAGE_DETECTION_CONFIDENCE_LEVEL_CONFIDENT,
+ LANGUAGE_DETECTION_CONFIDENCE_LEVEL_HIGHLY_CONFIDENT
+ })
+ public @interface LanguageDetectionConfidenceLevel {}
+
+ public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_UNKNOWN = 0;
+ public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_NOT_CONFIDENT = 1;
+ public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_CONFIDENT = 2;
+ public static final int LANGUAGE_DETECTION_CONFIDENCE_LEVEL_HIGHLY_CONFIDENT = 3;
+
+ /**
+ * Key used to retrieve an ArrayList<{@link String}> containing representations of the
+ * IETF language tags (as defined by BCP 47, e.g., "en-US", "en-UK") denoting the alternative
+ * locales for the same language retrieved by the key {@link #DETECTED_LANGUAGE}.
+ *
+ * This info is returned to the client in the {@link Bundle} passed to
+ * {@link RecognitionListener#onLanguageDetection(Bundle)} only if
+ * {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_DETECTION} is set.
+ */
+ public static final String TOP_LOCALE_ALTERNATIVES = "top_locale_alternatives";
+
+ /**
+ * Key used to retrieve the result of the language switch of the most recent audio chunk,
+ * represented by an {@code int} value prefixed by {@code LANGUAGE_SWITCH_}.
+ *
+ * <p> This info is returned to the client in the {@link Bundle} passed to the
+ * {@link RecognitionListener#onLanguageDetection(Bundle)} only if
+ * {@link RecognizerIntent#EXTRA_ENABLE_LANGUAGE_SWITCH} is set.
+ */
+ public static final String LANGUAGE_SWITCH_RESULT = "language_switch_result";
+
+ /**
+ * The result of the language switch.
+ *
+ * @hide
+ */
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"LANGUAGE_SWITCH_RESULT_"}, value = {
+ LANGUAGE_SWITCH_RESULT_NOT_ATTEMPTED,
+ LANGUAGE_SWITCH_RESULT_SUCCEEDED,
+ LANGUAGE_SWITCH_RESULT_FAILED,
+ LANGUAGE_SWITCH_RESULT_SKIPPED_NO_MODEL
+ })
+ public @interface LanguageSwitchResult {}
+
+ /** Switch not attempted. */
+ public static final int LANGUAGE_SWITCH_RESULT_NOT_ATTEMPTED = 0;
+
+ /** Switch attempted and succeeded. */
+ public static final int LANGUAGE_SWITCH_RESULT_SUCCEEDED = 1;
+
+ /** Switch attempted and failed. */
+ public static final int LANGUAGE_SWITCH_RESULT_FAILED = 2;
+
+ /**
+ * Switch skipped because the language model is missing
+ * or the language is not allowlisted for auto switch.
+ */
+ public static final int LANGUAGE_SWITCH_RESULT_SKIPPED_NO_MODEL = 3;
+
+ /**
* The reason speech recognition failed.
*
* @hide
@@ -963,6 +1058,7 @@
private static final int MSG_ON_EVENT = 9;
private static final int MSG_SEGMENT_RESULTS = 10;
private static final int MSG_SEGMENT_END_SESSION = 11;
+ private static final int MSG_LANGUAGE_DETECTION = 12;
private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -1004,6 +1100,9 @@
case MSG_SEGMENT_END_SESSION:
mInternalListener.onEndOfSegmentedSession();
break;
+ case MSG_LANGUAGE_DETECTION:
+ mInternalListener.onLanguageDetection((Bundle) msg.obj);
+ break;
}
}
};
@@ -1048,6 +1147,10 @@
Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget();
}
+ public void onLanguageDetection(final Bundle results) {
+ Message.obtain(mInternalHandler, MSG_LANGUAGE_DETECTION, results).sendToTarget();
+ }
+
public void onEvent(final int eventType, final Bundle params) {
Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
.sendToTarget();
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 18fdb83..f6309f2 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -32,6 +32,8 @@
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.TelephonyManager.DataEnabledReason;
+import android.telephony.TelephonyManager.EmergencyCallbackModeStopReason;
+import android.telephony.TelephonyManager.EmergencyCallbackModeType;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
@@ -1304,8 +1306,6 @@
// default implementation empty
}
-
-
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -1669,6 +1669,18 @@
public final void onMediaQualityStatusChanged(MediaQualityStatus mediaQualityStatus) {
// not support. Can't override. Use TelephonyCallback.
}
+
+ /** @hide */
+ public final void onCallBackModeStarted(
+ @TelephonyManager.EmergencyCallbackModeType int type) {
+ // not support. Can't override. Use TelephonyCallback.
+ }
+
+ /** @hide */
+ public final void onCallBackModeStopped(@EmergencyCallbackModeType int type,
+ @EmergencyCallbackModeStopReason int reason) {
+ // not support. Can't override. Use TelephonyCallback.
+ }
}
private void log(String s) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index f8df668..7ada058 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -612,6 +612,20 @@
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int EVENT_MEDIA_QUALITY_STATUS_CHANGED = 39;
+
+ /**
+ * Event for changes to the Emergency callback mode
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
+ * @see EmergencyCallbackModeListener#onCallbackModeStarted(int)
+ * @see EmergencyCallbackModeListener#onCallbackModeStopped(int, int)
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_EMERGENCY_CALLBACK_MODE_CHANGED = 40;
+
/**
* @hide
*/
@@ -654,7 +668,8 @@
EVENT_LEGACY_CALL_STATE_CHANGED,
EVENT_LINK_CAPACITY_ESTIMATE_CHANGED,
EVENT_TRIGGER_NOTIFY_ANBR,
- EVENT_MEDIA_QUALITY_STATUS_CHANGED
+ EVENT_MEDIA_QUALITY_STATUS_CHANGED,
+ EVENT_EMERGENCY_CALLBACK_MODE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TelephonyEvent {
@@ -1568,6 +1583,53 @@
}
/**
+ * Interface for emergency callback mode listener.
+ *
+ * @hide
+ */
+ public interface EmergencyCallbackModeListener {
+ /**
+ * Indicates that Callback Mode has been started.
+ * <p>
+ * This method will be called when an emergency sms/emergency call is sent
+ * and the callback mode is supported by the carrier.
+ * If an emergency SMS is transmitted during callback mode for SMS, this API will be called
+ * once again with TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS.
+ *
+ * @param type for callback mode entry
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type);
+
+ /**
+ * Indicates that Callback Mode has been stopped.
+ * <p>
+ * This method will be called when the callback mode timer expires or when
+ * a normal call/SMS is sent
+ *
+ * @param type for callback mode entry
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+ *
+ * @param reason for changing callback mode
+ *
+ * @see TelephonyManager#STOP_REASON_UNKNOWN
+ * @see TelephonyManager#STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED
+ * @see TelephonyManager#STOP_REASON_NORMAL_SMS_SENT
+ * @see TelephonyManager#STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED
+ * @see TelephonyManager#STOP_REASON_EMERGENCY_SMS_SENT
+ * @see TelephonyManager#STOP_REASON_TIMER_EXPIRED
+ * @see TelephonyManager#STOP_REASON_USER_ACTION
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason);
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
* <p>
@@ -1935,5 +1997,27 @@
() -> mExecutor.execute(() -> listener.onMediaQualityStatusChanged(
mediaQualityStatus)));
}
+
+ public void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type) {
+ EmergencyCallbackModeListener listener =
+ (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
+ Log.d(LOG_TAG, "onCallBackModeStarted:type=" + type + ", listener=" + listener);
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallBackModeStarted(type)));
+ }
+
+ public void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
+ EmergencyCallbackModeListener listener =
+ (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
+ Log.d(LOG_TAG, "onCallBackModeStopped:type=" + type
+ + ", reason=" + reason + ", listener=" + listener);
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallBackModeStopped(type, reason)));
+ }
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 8b24e07..f648ad4 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1113,6 +1113,11 @@
eventList.add(TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED);
}
+ if (telephonyCallback instanceof TelephonyCallback.EmergencyCallbackModeListener) {
+ eventList.add(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED);
+ }
+
+
return eventList;
}
@@ -1539,4 +1544,43 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Notify Callback Mode has been started.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param type for callback mode entry.
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ */
+ public void notifyCallBackModeStarted(int phoneId, int subId,
+ @TelephonyManager.EmergencyCallbackModeType int type) {
+ try {
+ Log.d(TAG, "notifyCallBackModeStarted:type=" + type);
+ sRegistry.notifyCallbackModeStarted(phoneId, subId, type);
+ } catch (RemoteException ex) {
+ // system process is dead
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notify Callback Mode has been stopped.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param type for callback mode entry.
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ * @param reason for changing callback mode.
+ * See {@link TelephonyManager.EmergencyCallbackModeStopReason}.
+ */
+ public void notifyCallbackModeStopped(int phoneId, int subId,
+ @TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
+ try {
+ Log.d(TAG, "notifyCallbackModeStopped:type=" + type + ", reason=" + reason);
+ sRegistry.notifyCallbackModeStopped(phoneId, subId, type, reason);
+ } catch (RemoteException ex) {
+ // system process is dead
+ throw ex.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c2afd20..7d18bf0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10199,6 +10199,7 @@
setNotifiedContentCaptureAppeared();
if (ai != null) {
+ makeParentImportantAndNotifyAppearedEventIfNeed();
ai.delayNotifyContentCaptureEvent(session, this, appeared);
} else {
if (DEBUG_CONTENT_CAPTURE) {
@@ -10226,6 +10227,22 @@
}
}
+ private void makeParentImportantAndNotifyAppearedEventIfNeed() {
+ // If view sent the appeared event to Content Capture, Content Capture also
+ // would like to receive its parents' appeared events. So checks its parents
+ // whether the appeared event is sent or not. If not, send the appeared event.
+ final ViewParent parent = getParent();
+ if (parent instanceof View) {
+ View p = ((View) parent);
+ if (p.getNotifiedContentCaptureAppeared()) {
+ return;
+ }
+ // Set important for content capture in the cache.
+ p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
+ p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true);
+ }
+ }
+
private void setNotifiedContentCaptureAppeared() {
mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4576d62..247e026 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -832,6 +832,8 @@
private static final int BOOLEAN_PROPERTY_REQUEST_INITIAL_ACCESSIBILITY_FOCUS = 1 << 24;
+ private static final int BOOLEAN_PROPERTY_REQUEST_TOUCH_PASSTHROUGH = 1 << 25;
+
/**
* Bits that provide the id of a virtual descendant of a view.
*/
@@ -2595,6 +2597,53 @@
}
/**
+ * Gets whether this node is one of the candidates that wants touch interaction within its
+ * screen bounds to bypass the touch exploration and go straight to the underlying view
+ * hierarchy.
+ *
+ * <p>
+ * {@link android.accessibilityservice.AccessibilityService} could aggregate the {@link
+ * #getBoundsInScreen()} that has request touch passthrough, and/or doing complex calculation
+ * with other views that doesn't request touch passthrough, and call {@link
+ * AccessibilityService#setTouchExplorationPassthroughRegion(int, Region)} to bypass the touch
+ * interactions to the underlying views within the region.
+ * </p>
+ *
+ * @return True if the node wants touch interaction within its screen bounds to bypass touch
+ * exploration and go straight to the underlying view hierarchy; false otherwise.
+ */
+ public boolean hasRequestTouchPassthrough() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_REQUEST_TOUCH_PASSTHROUGH);
+ }
+
+ /**
+ * Sets whether this node wants touch interaction within its screen bounds to bypass touch
+ * exploration and go straight to the underlying view hierarchy.
+ * <p>
+ * <strong>Note:</strong> This property allows the
+ * {@link android.accessibilityservice.AccessibilityService} to calculate the
+ * aggregated touch passthrough region. App developers need to ensure that the
+ * {@link #getBoundsInScreen()} of
+ * the node align with the region they want touchable, and that child nodes overlapping these
+ * bounds may cause that region to be reduced.
+ * </p>
+ *
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param touchPassthrough True if the node wants touch interaction within its screen bounds
+ * to bypass touch exploration and go straight to the underlying view
+ * hierarchy.
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setRequestTouchPassthrough(boolean touchPassthrough) {
+ setBooleanProperty(BOOLEAN_PROPERTY_REQUEST_TOUCH_PASSTHROUGH, touchPassthrough);
+ }
+
+ /**
* If this node represents a visually distinct region of the screen that may update separately
* from the rest of the window, it is considered a pane. Set the pane title to indicate that
* the node is a pane, and to provide a title for it.
diff --git a/core/java/com/android/internal/expresslog/Counter.java b/core/java/com/android/internal/expresslog/Counter.java
index cc37c69..afdbdc8 100644
--- a/core/java/com/android/internal/expresslog/Counter.java
+++ b/core/java/com/android/internal/expresslog/Counter.java
@@ -28,6 +28,7 @@
/**
* Increments Telemetry Express Counter metric by 1
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
* @hide
*/
public static void logIncrement(@NonNull String metricId) {
@@ -36,6 +37,8 @@
/**
* Increments Telemetry Express Counter metric by arbitrary value
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
+ * @param amount to increment counter
* @hide
*/
public static void logIncrement(@NonNull String metricId, long amount) {
diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java
index db70cac..2f3b662 100644
--- a/core/java/com/android/internal/expresslog/Histogram.java
+++ b/core/java/com/android/internal/expresslog/Histogram.java
@@ -26,6 +26,12 @@
private final long mMetricIdHash;
private final BinOptions mBinOptions;
+ /**
+ * Creates Histogram metric logging wrapper
+ * @param metricId to log, logging will be no-op if metricId is not defined in the TeX catalog
+ * @param binOptions to calculate bin index for samples
+ * @hide
+ */
public Histogram(@NonNull String metricId, @NonNull BinOptions binOptions) {
mMetricIdHash = Utils.hashString(metricId);
mBinOptions = binOptions;
@@ -33,7 +39,7 @@
/**
* Logs increment sample count for automatically calculated bin
- *
+ * @param sample value
* @hide
*/
public void logSample(float sample) {
@@ -46,17 +52,16 @@
public interface BinOptions {
/**
* Returns bins count to be used by a histogram
- *
* @return bins count used to initialize Options, including overflow & underflow bins
* @hide
*/
int getBinsCount();
/**
- * @return zero based index
- * Calculates bin index for the input sample value
+ * Returns bin index for the input sample value
* index == 0 stands for underflow
* index == getBinsCount() - 1 stands for overflow
+ * @return zero based index
* @hide
*/
int getBinForSample(float sample);
@@ -70,6 +75,17 @@
private final float mExclusiveMaxValue;
private final float mBinSize;
+ /**
+ * Creates otpions for uniform (linear) sized bins
+ * @param binCount amount of histogram bins. 2 bin indexes will be calculated
+ * automatically to represent undeflow & overflow bins
+ * @param minValue is included in the first bin, values less than minValue
+ * go to underflow bin
+ * @param exclusiveMaxValue is included in the overflow bucket. For accurate
+ measure up to kMax, then exclusiveMaxValue
+ * should be set to kMax + 1
+ * @hide
+ */
public UniformOptions(int binCount, float minValue, float exclusiveMaxValue) {
if (binCount < 1) {
throw new IllegalArgumentException("Bin count should be positive number");
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 63785f2..134a917 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -139,15 +139,6 @@
}
@Override
- public boolean isDeviceContext() {
- Context context = mContext.get();
- if (context != null) {
- return context.isDeviceContext();
- }
- return false;
- }
-
- @Override
public boolean isConfigurationContext() {
Context context = mContext.get();
if (context != null) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 1875ecf..a14e9a7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2507,12 +2507,23 @@
final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
if (!mForcedStatusBarColor) {
- mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+ mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, Color.BLACK);
}
if (!mForcedNavigationBarColor) {
- mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+ final int navBarCompatibleColor = context.getColor(R.color.navigation_bar_compatible);
+ final int navBarDefaultColor = context.getColor(R.color.navigation_bar_default);
+ final int navBarColor = a.getColor(R.styleable.Window_navigationBarColor,
+ navBarDefaultColor);
+
+ mNavigationBarColor =
+ navBarColor == navBarDefaultColor
+ && !context.getResources().getBoolean(
+ R.bool.config_navBarDefaultTransparent)
+ ? navBarCompatibleColor
+ : navBarColor;
+
mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor,
- 0x00000000);
+ Color.TRANSPARENT);
}
if (!targetPreQ) {
mEnsureStatusBarContrastWhenTransparent = a.getBoolean(
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3e9f1cb..03cfd4f 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -78,4 +78,6 @@
void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList);
void onMediaQualityStatusChanged(in MediaQualityStatus mediaQualityStatus);
+ void onCallBackModeStarted(int type);
+ void onCallBackModeStopped(int type, int reason);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index fd9239d..8a02dd6 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -117,4 +117,7 @@
String pkg, String featureId);
void removeCarrierConfigChangeListener(ICarrierConfigChangeListener listener, String pkg);
void notifyCarrierConfigChanged(int phoneId, int subId, int carrierId, int specificCarrierId);
+
+ void notifyCallbackModeStarted(int phoneId, int subId, int type);
+ void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason);
}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 1910331..b1dab85 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -18,29 +18,25 @@
#define LOG_TAG "AudioRecord-JNI"
-#include <inttypes.h>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
-#include <utils/Log.h>
-#include <media/AudioRecord.h>
-#include <media/MicrophoneInfo.h>
-#include <vector>
-
#include <android/content/AttributionSourceState.h>
#include <android_os_Parcel.h>
-
+#include <inttypes.h>
+#include <jni.h>
+#include <media/AudioRecord.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <utils/Log.h>
+
+#include <vector>
#include "android_media_AudioAttributes.h"
-#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
#include "android_media_DeviceCallback.h"
#include "android_media_JNIUtils.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_MicrophoneInfo.h"
-
+#include "core_jni_helpers.h"
// ----------------------------------------------------------------------------
@@ -719,7 +715,7 @@
}
jint jStatus = AUDIO_JAVA_SUCCESS;
- std::vector<media::MicrophoneInfo> activeMicrophones;
+ std::vector<media::MicrophoneInfoFw> activeMicrophones;
status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 75f8402..8ba4eed 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -28,7 +28,6 @@
#include <media/AudioContainers.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
-#include <media/MicrophoneInfo.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
@@ -2424,7 +2423,7 @@
}
jint jStatus;
- std::vector<media::MicrophoneInfo> microphones;
+ std::vector<media::MicrophoneInfoFw> microphones;
status_t status = AudioSystem::getMicrophones(µphones);
if (status != NO_ERROR) {
ALOGE("AudioSystem::getMicrophones error %d", status);
diff --git a/core/jni/android_media_MicrophoneInfo.cpp b/core/jni/android_media_MicrophoneInfo.cpp
index b70190f..65e30d8 100644
--- a/core/jni/android_media_MicrophoneInfo.cpp
+++ b/core/jni/android_media_MicrophoneInfo.cpp
@@ -15,6 +15,9 @@
*/
#include "android_media_MicrophoneInfo.h"
+
+#include <media/AidlConversion.h>
+
#include "android_media_AudioErrors.h"
#include "core_jni_helpers.h"
@@ -46,8 +49,17 @@
namespace android {
jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
- const media::MicrophoneInfo *microphoneInfo)
-{
+ const media::MicrophoneInfoFw *microphoneInfo) {
+ // The Java object uses the same enum values as the C enum values, which are
+ // generated from HIDL. Thus, we can use the legacy structure as the source for
+ // creating the Java object. Once we start removing legacy types, we can add
+ // direct converters between Java and AIDL, this will eliminate the need
+ // to have JNI code like this one.
+ auto conv = aidl2legacy_MicrophoneInfoFw_audio_microphone_characteristic_t(*microphoneInfo);
+ if (!conv.ok()) {
+ return nativeToJavaStatus(conv.error());
+ }
+
jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
jstring jDeviceId = NULL;
jstring jAddress = NULL;
@@ -56,36 +68,23 @@
jobject jFrequencyResponses = NULL;
jobject jChannelMappings = NULL;
- jDeviceId = env->NewStringUTF(microphoneInfo->getDeviceId().c_str());
- jAddress = env->NewStringUTF(microphoneInfo->getAddress().c_str());
- if (microphoneInfo->getGeometricLocation().size() != 3 ||
- microphoneInfo->getOrientation().size() != 3) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
- jGeometricLocation = env->NewObject(gMicrophoneInfoCoordinateClass,
- gMicrophoneInfoCoordinateCstor,
- microphoneInfo->getGeometricLocation()[0],
- microphoneInfo->getGeometricLocation()[1],
- microphoneInfo->getGeometricLocation()[2]);
- jOrientation = env->NewObject(gMicrophoneInfoCoordinateClass,
- gMicrophoneInfoCoordinateCstor,
- microphoneInfo->getOrientation()[0],
- microphoneInfo->getOrientation()[1],
- microphoneInfo->getOrientation()[2]);
+ const auto &micInfo = conv.value();
+ jDeviceId = env->NewStringUTF(micInfo.device_id);
+ jAddress = env->NewStringUTF(micInfo.address);
+ jGeometricLocation =
+ env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
+ micInfo.geometric_location.x, micInfo.geometric_location.y,
+ micInfo.geometric_location.z);
+ jOrientation =
+ env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
+ micInfo.orientation.x, micInfo.orientation.y, micInfo.orientation.z);
// Create a list of Pair for frequency response.
- if (microphoneInfo->getFrequencyResponses().size() != 2 ||
- microphoneInfo->getFrequencyResponses()[0].size() !=
- microphoneInfo->getFrequencyResponses()[1].size()) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
jFrequencyResponses = env->NewObject(gArrayListClass, gArrayListCstor);
- for (size_t i = 0; i < microphoneInfo->getFrequencyResponses()[0].size(); i++) {
- jobject jFrequency = env->NewObject(gFloatClass, gFloatCstor,
- microphoneInfo->getFrequencyResponses()[0][i]);
- jobject jResponse = env->NewObject(gFloatClass, gFloatCstor,
- microphoneInfo->getFrequencyResponses()[1][i]);
+ for (size_t i = 0; i < micInfo.num_frequency_responses; i++) {
+ jobject jFrequency =
+ env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[0][i]);
+ jobject jResponse =
+ env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[1][i]);
jobject jFrequencyResponse = env->NewObject(gPairClass, gPairCstor, jFrequency, jResponse);
env->CallBooleanMethod(jFrequencyResponses, gArrayListMethods.add, jFrequencyResponse);
env->DeleteLocalRef(jFrequency);
@@ -93,13 +92,9 @@
env->DeleteLocalRef(jFrequencyResponse);
}
// Create a list of Pair for channel mapping.
- if (microphoneInfo->getChannelMapping().size() != AUDIO_CHANNEL_COUNT_MAX) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
- jChannelMappings = env->NewObject(gArrayListClass, gArrayListCstor);
- for (size_t i = 0; i < microphoneInfo->getChannelMapping().size(); i++) {
- int channelMappingType = microphoneInfo->getChannelMapping()[i];
+ const auto &channelMapping = micInfo.channel_mapping;
+ for (size_t i = 0; i < std::size(channelMapping); i++) {
+ int channelMappingType = channelMapping[i];
if (channelMappingType != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
jobject jChannelIndex = env->NewObject(gIntegerClass, gIntegerCstor, i);
jobject jChannelMappingType = env->NewObject(gIntegerClass, gIntegerCstor,
@@ -113,18 +108,11 @@
}
}
*jMicrophoneInfo = env->NewObject(gMicrophoneInfoClass, gMicrophoneInfoCstor, jDeviceId,
- microphoneInfo->getType(), jAddress,
- microphoneInfo->getDeviceLocation(),
- microphoneInfo->getDeviceGroup(),
- microphoneInfo->getIndexInTheGroup(),
- jGeometricLocation, jOrientation,
- jFrequencyResponses, jChannelMappings,
- microphoneInfo->getSensitivity(),
- microphoneInfo->getMaxSpl(),
- microphoneInfo->getMinSpl(),
- microphoneInfo->getDirectionality());
+ micInfo.device, jAddress, micInfo.location, micInfo.group,
+ micInfo.index_in_the_group, jGeometricLocation, jOrientation,
+ jFrequencyResponses, jChannelMappings, micInfo.sensitivity,
+ micInfo.max_spl, micInfo.min_spl, micInfo.directionality);
-exit:
if (jDeviceId != NULL) {
env->DeleteLocalRef(jDeviceId);
}
@@ -145,7 +133,6 @@
}
return jStatus;
}
-
}
int register_android_media_MicrophoneInfo(JNIEnv *env)
diff --git a/core/jni/android_media_MicrophoneInfo.h b/core/jni/android_media_MicrophoneInfo.h
index 241b6d0..dc531c6 100644
--- a/core/jni/android_media_MicrophoneInfo.h
+++ b/core/jni/android_media_MicrophoneInfo.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_MEDIA_MICROPHONEINFO_H
#define ANDROID_MEDIA_MICROPHONEINFO_H
+#include <android/media/MicrophoneInfoFw.h>
#include <system/audio.h>
-#include <media/MicrophoneInfo.h>
#include "jni.h"
@@ -27,7 +27,7 @@
// Conversion from C++ MicrophoneInfo object to Java MicrophoneInfo object
extern jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
- const media::MicrophoneInfo *microphoneInfo);
+ const media::MicrophoneInfoFw *microphoneInfo);
} // namespace android
-#endif
\ No newline at end of file
+#endif
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a4818c7..830ef46 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -109,6 +109,7 @@
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
<protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED" />
<protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.os.action.LOW_POWER_STANDBY_PORTS_CHANGED" />
<protected-broadcast android:name="android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED" />
<!-- @deprecated This is rarely used and will be phased out soon. -->
@@ -2930,6 +2931,15 @@
<permission android:name="android.permission.BIND_IMS_SERVICE"
android:protectionLevel="signature|privileged|vendorPrivileged" />
+ <!-- Must be required by a SatelliteService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature|privileged|vendorPrivileged
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_SATELLITE_SERVICE"
+ android:protectionLevel="signature|privileged|vendorPrivileged" />
+
<!-- Must be required by a telephony data service to ensure that only the
system can bind to it.
<p>Protection level: signature
@@ -3667,6 +3677,10 @@
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MTE"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to manage policy related to device identifiers. -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
@@ -4459,6 +4473,11 @@
<permission android:name="android.permission.CREDENTIAL_MANAGER_SET_ORIGIN"
android:protectionLevel="normal" />
+ <!-- Allows permission to use Credential Manager UI for providing and saving credentials
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to be able to store and retrieve credentials from a remote
device.
@hide @SystemApi -->
@@ -5838,7 +5857,7 @@
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CALL_AUDIO_INTERCEPTION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|role" />
<!-- @TestApi Allows an application to query audio related state.
@hide -->
@@ -5940,6 +5959,12 @@
<permission android:name="android.permission.MANAGE_LOW_POWER_STANDBY"
android:protectionLevel="signature|privileged" />
+ <!-- @hide @SystemApi Allows an application to request ports to remain open during
+ Low Power Standby.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SET_LOW_POWER_STANDBY_PORTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- @hide Allows low-level access to tun tap driver -->
<permission android:name="android.permission.NET_TUNNELING"
android:protectionLevel="signature|role" />
diff --git a/core/res/res/drawable/accessibility_magnification_thumbnail_background_bg.xml b/core/res/res/drawable/accessibility_magnification_thumbnail_background_bg.xml
new file mode 100644
index 0000000..7b82b4d
--- /dev/null
+++ b/core/res/res/drawable/accessibility_magnification_thumbnail_background_bg.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+<item>
+ <shape android:shape="rectangle">
+ <stroke
+ android:width="1dp"
+ android:color="@color/accessibility_magnification_thumbnail_stroke_color" />
+ <corners android:radius="4dp"/>
+ <solid android:color="@color/accessibility_magnification_thumbnail_background_color" />
+ </shape>
+</item>
+</layer-list>
diff --git a/core/res/res/drawable/accessibility_magnification_thumbnail_bg.xml b/core/res/res/drawable/accessibility_magnification_thumbnail_bg.xml
new file mode 100644
index 0000000..77ba94e
--- /dev/null
+++ b/core/res/res/drawable/accessibility_magnification_thumbnail_bg.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+<item>
+ <shape android:shape="rectangle">
+ <corners android:radius="2dp"/>
+ <solid android:color="@color/accessibility_magnification_thumbnail_color" />
+ </shape>
+</item>
+</layer-list>
diff --git a/core/res/res/layout/thumbnail_background_view.xml b/core/res/res/layout/thumbnail_background_view.xml
new file mode 100644
index 0000000..0ba01e9
--- /dev/null
+++ b/core/res/res/layout/thumbnail_background_view.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/accessibility_magnification_thumbnail_background_bg">
+ <View
+ android:id="@+id/accessibility_magnification_thumbnail_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/accessibility_magnification_thumbnail_bg">
+ </View>
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0c2fc1d..6b3c155 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -470,15 +470,15 @@
<color name="system_error_container_light">#FFDAD5</color>
<color name="system_on_error_container_light">#410000</color>
<color name="system_primary_fixed_light">#D8E2FF</color>
- <color name="system_primary_fixed_darker_light">#ADC6FF</color>
+ <color name="system_primary_fixed_dim_light">#ADC6FF</color>
<color name="system_on_primary_fixed_light">#001A41</color>
<color name="system_on_primary_fixed_variant_light">#2B4678</color>
<color name="system_secondary_fixed_light">#DBE2F9</color>
- <color name="system_secondary_fixed_darker_light">#BFC6DC</color>
+ <color name="system_secondary_fixed_dim_light">#BFC6DC</color>
<color name="system_on_secondary_fixed_light">#141B2C</color>
<color name="system_on_secondary_fixed_variant_light">#3F4759</color>
<color name="system_tertiary_fixed_light">#FBD7FC</color>
- <color name="system_tertiary_fixed_darker_light">#DEBCDF</color>
+ <color name="system_tertiary_fixed_dim_light">#DEBCDF</color>
<color name="system_on_tertiary_fixed_light">#29132D</color>
<color name="system_on_tertiary_fixed_variant_light">#583E5B</color>
<color name="system_control_activated_light">#D8E2FF</color>
@@ -525,15 +525,15 @@
<color name="system_error_container_dark">#930001</color>
<color name="system_on_error_container_dark">#FFDAD5</color>
<color name="system_primary_fixed_dark">#D8E2FF</color>
- <color name="system_primary_fixed_darker_dark">#ADC6FF</color>
+ <color name="system_primary_fixed_dim_dark">#ADC6FF</color>
<color name="system_on_primary_fixed_dark">#001A41</color>
<color name="system_on_primary_fixed_variant_dark">#2B4678</color>
<color name="system_secondary_fixed_dark">#DBE2F9</color>
- <color name="system_secondary_fixed_darker_dark">#BFC6DC</color>
+ <color name="system_secondary_fixed_dim_dark">#BFC6DC</color>
<color name="system_on_secondary_fixed_dark">#141B2C</color>
<color name="system_on_secondary_fixed_variant_dark">#3F4759</color>
<color name="system_tertiary_fixed_dark">#FBD7FC</color>
- <color name="system_tertiary_fixed_darker_dark">#DEBCDF</color>
+ <color name="system_tertiary_fixed_dim_dark">#DEBCDF</color>
<color name="system_on_tertiary_fixed_dark">#29132D</color>
<color name="system_on_tertiary_fixed_variant_dark">#583E5B</color>
<color name="system_control_activated_dark">#2B4678</color>
@@ -556,6 +556,11 @@
<color name="accessibility_daltonizer_background">#00BCD4</color>
<color name="accessibility_color_inversion_background">#546E7A</color>
+ <!-- Fullscreen magnification thumbnail color -->
+ <color name="accessibility_magnification_thumbnail_stroke_color">#E0E0E0</color>
+ <color name="accessibility_magnification_thumbnail_background_color">#FCFCFC</color>
+ <color name="accessibility_magnification_thumbnail_color">#252525</color>
+
<!-- Color of camera light when camera is in use -->
<color name="camera_privacy_light_day">#FFFFFF</color>
<color name="camera_privacy_light_night">#FFFFFF</color>
@@ -573,4 +578,10 @@
<color name="side_fps_toast_background">#F7F9FA</color>
<color name="side_fps_text_color">#191C1D</color>
<color name="side_fps_button_color">#00677E</color>
+
+ <!-- Color for system bars -->
+ <color name="navigation_bar_compatible">@android:color/black</color>
+ <!-- This uses non-regular transparent intentionally. It is used to tell if the transparent
+ color is set by the framework or not. -->
+ <color name="navigation_bar_default">#00808080</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8e5ae9c..31b9f9a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2189,6 +2189,8 @@
<bool name="config_enableDefaultNotesForWorkProfile">false</bool>
<!-- The name of the package that will hold the system financed device controller role. -->
<string name="config_systemFinancedDeviceController" translatable="false">com.android.devicelockcontroller</string>
+ <!-- The name of the package that will hold the call streaming role. -->
+ <string name="config_systemCallStreaming" translatable="false"></string>
<!-- The component name of the wear service class that will be started by the system server. -->
<string name="config_wearServiceComponent" translatable="false"></string>
@@ -3876,6 +3878,10 @@
This should only be set when the device has gestural navigation enabled by default. -->
<bool name="config_showGesturalNavigationHints">false</bool>
+ <!-- Controls whether the navigation bar background color provided by the app is transparent by
+ default. This should be controlled in developer options. -->
+ <bool name="config_navBarDefaultTransparent">false</bool>
+
<!-- Controls the free snap mode for the docked stack divider. In this mode, the divider can be
snapped to any position between the first target and the last target. -->
<bool name="config_dockedStackDividerFreeSnapMode">false</bool>
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
index 8ed58f3..5576b9f 100644
--- a/core/res/res/values/config_device_idle.xml
+++ b/core/res/res/values/config_device_idle.xml
@@ -28,11 +28,17 @@
<integer name="device_idle_flex_time_short_ms">60000</integer>
<!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT -->
- <integer name="device_idle_light_after_inactive_to_ms">180000</integer>
+ <integer name="device_idle_light_after_inactive_to_ms">240000</integer>
<!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_TIMEOUT -->
<integer name="device_idle_light_idle_to_ms">300000</integer>
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_TIMEOUT_MAX_FLEX -->
+ <integer name="device_idle_light_idle_to_init_flex_ms">60000</integer>
+
+ <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_TIMEOUT_MAX_FLEX -->
+ <integer name="device_idle_light_idle_to_max_flex_ms">900000</integer>
+
<!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->
<item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e156c44..5bb86dc 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -606,6 +606,9 @@
<!-- Width of the outline stroke used by the accessibility focus rectangle -->
<dimen name="accessibility_focus_highlight_stroke_width">4dp</dimen>
+ <!-- padding of fullscreen magnification thumbnail -->
+ <dimen name="accessibility_magnification_thumbnail_padding">12dp</dimen>
+
<!-- The padding ratio of the Accessibility icon foreground drawable -->
<item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 7d41f76..b23d5b4 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -148,6 +148,8 @@
<public name="config_defaultNotes" />
<!-- @hide @SystemApi -->
<public name="config_systemFinancedDeviceController" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemCallStreaming" />
</staging-public-group>
<staging-public-group type="dimen" first-id="0x01ca0000">
@@ -187,15 +189,15 @@
<public name="system_error_container_light" />
<public name="system_on_error_container_light" />
<public name="system_primary_fixed_light" />
- <public name="system_primary_fixed_darker_light" />
+ <public name="system_primary_fixed_dim_light" />
<public name="system_on_primary_fixed_light" />
<public name="system_on_primary_fixed_variant_light" />
<public name="system_secondary_fixed_light" />
- <public name="system_secondary_fixed_darker_light" />
+ <public name="system_secondary_fixed_dim_light" />
<public name="system_on_secondary_fixed_light" />
<public name="system_on_secondary_fixed_variant_light" />
<public name="system_tertiary_fixed_light" />
- <public name="system_tertiary_fixed_darker_light" />
+ <public name="system_tertiary_fixed_dim_light" />
<public name="system_on_tertiary_fixed_light" />
<public name="system_on_tertiary_fixed_variant_light" />
<public name="system_control_activated_light" />
@@ -242,15 +244,15 @@
<public name="system_error_container_dark"/>
<public name="system_on_error_container_dark"/>
<public name="system_primary_fixed_dark"/>
- <public name="system_primary_fixed_darker_dark"/>
+ <public name="system_primary_fixed_dim_dark"/>
<public name="system_on_primary_fixed_dark"/>
<public name="system_on_primary_fixed_variant_dark"/>
<public name="system_secondary_fixed_dark"/>
- <public name="system_secondary_fixed_darker_dark"/>
+ <public name="system_secondary_fixed_dim_dark"/>
<public name="system_on_secondary_fixed_dark"/>
<public name="system_on_secondary_fixed_variant_dark"/>
<public name="system_tertiary_fixed_dark"/>
- <public name="system_tertiary_fixed_darker_dark"/>
+ <public name="system_tertiary_fixed_dim_dark"/>
<public name="system_on_tertiary_fixed_dark"/>
<public name="system_on_tertiary_fixed_variant_dark"/>
<public name="system_control_activated_dark"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dcd7a31..312ad1f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2996,6 +2996,9 @@
<java-symbol type="array" name="config_backGestureInsetScales" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<java-symbol type="bool" name="config_showGesturalNavigationHints" />
+ <java-symbol type="bool" name="config_navBarDefaultTransparent" />
+ <java-symbol type="color" name="navigation_bar_default"/>
+ <java-symbol type="color" name="navigation_bar_compatible"/>
<!-- EditText suggestion popup. -->
<java-symbol type="id" name="suggestionWindowContainer" />
@@ -4414,6 +4417,8 @@
<java-symbol type="integer" name="device_idle_flex_time_short_ms" />
<java-symbol type="integer" name="device_idle_light_after_inactive_to_ms" />
<java-symbol type="integer" name="device_idle_light_idle_to_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_to_init_flex_ms" />
+ <java-symbol type="integer" name="device_idle_light_idle_to_max_flex_ms" />
<java-symbol type="integer" name="device_idle_light_idle_factor" />
<java-symbol type="integer" name="device_idle_light_max_idle_to_ms" />
<java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />
@@ -4499,7 +4504,15 @@
<java-symbol type="bool" name="config_magnification_area" />
<java-symbol type="bool" name="config_trackerAppNeedsPermissions"/>
-
+ <!-- FullScreenMagnification thumbnail -->
+ <java-symbol type="layout" name="thumbnail_background_view" />
+ <java-symbol type="drawable" name="accessibility_magnification_thumbnail_background_bg" />
+ <java-symbol type="drawable" name="accessibility_magnification_thumbnail_bg" />
+ <java-symbol type="color" name="accessibility_magnification_thumbnail_stroke_color" />
+ <java-symbol type="color" name="accessibility_magnification_thumbnail_background_color" />
+ <java-symbol type="color" name="accessibility_magnification_thumbnail_color" />
+ <java-symbol type="dimen" name="accessibility_magnification_thumbnail_padding" />
+ <java-symbol type="id" name="accessibility_magnification_thumbnail_view" />
<!-- Package with global data query permissions for AppSearch -->
<java-symbol type="string" name="config_globalAppSearchDataQuerierPackage" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index a60862b..e96de582 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -191,7 +191,7 @@
<item name="windowTranslucentNavigation">false</item>
<item name="windowDrawsSystemBarBackgrounds">false</item>
<item name="statusBarColor">@color/black</item>
- <item name="navigationBarColor">@color/black</item>
+ <item name="navigationBarColor">@color/navigation_bar_default</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_action_bar</item>
<item name="windowContentTransitions">false</item>
<item name="windowActivityTransitions">false</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index e516a6c..cd4c0d6 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -175,7 +175,7 @@
<item name="windowDrawsSystemBarBackgrounds">true</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
<item name="statusBarColor">?attr/colorPrimaryDark</item>
- <item name="navigationBarColor">@color/black</item>
+ <item name="navigationBarColor">@color/navigation_bar_default</item>
<item name="windowEnterTransition">@transition/fade</item>
<item name="windowSharedElementEnterTransition">@transition/move</item>
<item name="windowSharedElementExitTransition">@transition/move</item>
@@ -548,7 +548,7 @@
<item name="windowDrawsSystemBarBackgrounds">true</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
<item name="statusBarColor">?attr/colorPrimaryDark</item>
- <item name="navigationBarColor">@color/black</item>
+ <item name="navigationBarColor">@color/navigation_bar_default</item>
<item name="windowEnterTransition">@transition/fade</item>
<item name="windowSharedElementEnterTransition">@transition/move</item>
<item name="windowSharedElementExitTransition">@transition/move</item>
diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
new file mode 100644
index 0000000..444e9f2
--- /dev/null
+++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
@@ -0,0 +1,626 @@
+/*
+ * 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.credentials;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.slice.Slice;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.service.credentials.CredentialEntry;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CredentialManagerTest {
+ @Mock
+ private ICredentialManager mMockCredentialManagerService;
+
+ @Mock
+ private Activity mMockActivity;
+
+ private GetCredentialRequest mGetRequest;
+ private CreateCredentialRequest mCreateRequest;
+
+ private ClearCredentialStateRequest mClearRequest;
+ private RegisterCredentialDescriptionRequest mRegisterRequest;
+ private UnregisterCredentialDescriptionRequest mUnregisterRequest;
+
+ private CredentialManager mCredentialManager;
+ private Executor mExecutor;
+ private String mPackageName;
+
+ private static boolean bundleEquals(Bundle a, Bundle b) {
+ if (a == null && b == null) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ for (String aKey : a.keySet()) {
+ if (!Objects.equals(a.get(aKey), b.get(aKey))) {
+ return false;
+ }
+ }
+
+ for (String bKey : b.keySet()) {
+ if (!Objects.equals(b.get(bKey), a.get(bKey))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static void assertBundleEquals(Bundle a, Bundle b) {
+ assertThat(bundleEquals(a, b)).isTrue();
+ }
+
+ @Before
+ public void setup() {
+ mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption(
+ new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY,
+ Bundle.EMPTY, false)).build();
+ mCreateRequest = new CreateCredentialRequest(Credential.TYPE_PASSWORD_CREDENTIAL,
+ Bundle.EMPTY, Bundle.EMPTY, false, false);
+ mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY);
+
+ final Slice slice = new Slice.Builder(Uri.parse("foo://bar"), null).addText("some text",
+ null, List.of(Slice.HINT_TITLE)).build();
+ mRegisterRequest = new RegisterCredentialDescriptionRequest(
+ new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL,
+ "{ \"foo\": \"bar\" }",
+ List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
+ mUnregisterRequest = new UnregisterCredentialDescriptionRequest(
+ new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL,
+ "{ \"foo\": \"bar\" }",
+ List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
+
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ mCredentialManager = new CredentialManager(context, mMockCredentialManagerService);
+ mExecutor = Runnable::run;
+ mPackageName = context.getOpPackageName();
+ }
+
+ @Test
+ public void testGetCredential_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(null, mMockActivity, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullActivity() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, null, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null,
+ null));
+ }
+
+ @Test
+ public void testGetCredential_noCredential() throws RemoteException {
+ ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IGetCredentialCallback.class);
+ ArgumentCaptor<GetCredentialException> errorCaptor = ArgumentCaptor.forClass(
+ GetCredentialException.class);
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onError(GetCredentialException.TYPE_NO_CREDENTIAL,
+ "no credential found");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ GetCredentialException.TYPE_NO_CREDENTIAL);
+ }
+
+ @Test
+ public void testGetCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor,
+ result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).executeGetCredential(any(), any(), any());
+ }
+
+ @Test
+ public void testGetCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor,
+ callback);
+
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testGetCredential_success() throws RemoteException {
+ final Credential cred = new Credential(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY);
+
+ ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IGetCredentialCallback.class);
+ ArgumentCaptor<GetCredentialResponse> responseCaptor = ArgumentCaptor.forClass(
+ GetCredentialResponse.class);
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onResponse(new GetCredentialResponse(cred));
+ verify(callback).onResult(responseCaptor.capture());
+
+ assertThat(responseCaptor.getValue().getCredential().getType()).isEqualTo(cred.getType());
+ }
+
+ @Test
+ public void testCreateCredential_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(null, mMockActivity, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullActivity() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, null, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, null,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null,
+ mExecutor, null));
+ }
+
+ @Test
+ public void testCreateCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor,
+ result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).executeCreateCredential(any(), any(), any());
+ }
+
+ @Test
+ public void testCreateCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor,
+ callback);
+
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testCreateCredential_failed() throws RemoteException {
+ ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ICreateCredentialCallback.class);
+ ArgumentCaptor<CreateCredentialException> errorCaptor = ArgumentCaptor.forClass(
+ CreateCredentialException.class);
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor,
+ callback);
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ callbackCaptor.getValue().onError(CreateCredentialException.TYPE_UNKNOWN, "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ CreateCredentialException.TYPE_UNKNOWN);
+ }
+
+ @Test
+ public void testCreateCredential_success() throws RemoteException {
+ final Bundle responseData = new Bundle();
+ responseData.putString("foo", "bar");
+
+ ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ICreateCredentialCallback.class);
+ ArgumentCaptor<CreateCredentialResponse> responseCaptor = ArgumentCaptor.forClass(
+ CreateCredentialResponse.class);
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor,
+ callback);
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ callbackCaptor.getValue().onResponse(new CreateCredentialResponse(responseData));
+ verify(callback).onResult(responseCaptor.capture());
+
+ assertBundleEquals(responseCaptor.getValue().getData(), responseData);
+ }
+
+ @Test
+ public void testClearCredentialState_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(null, null, mExecutor, result -> {
+ }));
+ }
+
+ @Test
+ public void testClearCredentialState_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(mClearRequest, null, null, result -> {
+ }));
+ }
+
+ @Test
+ public void testClearCredentialState_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor,
+ null));
+ }
+
+ @Test
+ public void testClearCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).clearCredentialState(any(), any(), any());
+ }
+
+ @Test
+ public void testClearCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testClearCredential_failed() throws RemoteException {
+ ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IClearCredentialStateCallback.class);
+ ArgumentCaptor<ClearCredentialStateException> errorCaptor = ArgumentCaptor.forClass(
+ ClearCredentialStateException.class);
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onError(ClearCredentialStateException.TYPE_UNKNOWN,
+ "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ ClearCredentialStateException.TYPE_UNKNOWN);
+ }
+
+ @Test
+ public void testClearCredential_success() throws RemoteException {
+ ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IClearCredentialStateCallback.class);
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onSuccess();
+ verify(callback).onResult(any());
+ }
+
+ @Test
+ public void testListEnabledProviders_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.listEnabledProviders(null, null, result -> {
+ }));
+
+ }
+
+ @Test
+ public void testListEnabledProviders_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.listEnabledProviders(null, mExecutor, null));
+
+ }
+
+ @Test
+ public void testListEnabledProviders_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.listEnabledProviders(cancellation, mExecutor, result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).listEnabledProviders(any());
+ }
+
+ @Test
+ public void testListEnabledProviders_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(any())).thenReturn(serviceSignal);
+
+ mCredentialManager.listEnabledProviders(cancellation, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testListEnabledProviders_failed() throws RemoteException {
+ ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IListEnabledProvidersCallback.class);
+ ArgumentCaptor<ListEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass(
+ ListEnabledProvidersException.class);
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(
+ callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.listEnabledProviders(null, mExecutor, callback);
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ final String errorType = "type";
+ callbackCaptor.getValue().onError("type", "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
+ }
+
+ @Test
+ public void testListEnabledProviders_success() throws RemoteException {
+ ListEnabledProvidersResponse response = ListEnabledProvidersResponse.create(
+ List.of("foo", "bar", "baz"));
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IListEnabledProvidersCallback.class);
+ ArgumentCaptor<ListEnabledProvidersResponse> responseCaptor = ArgumentCaptor.forClass(
+ ListEnabledProvidersResponse.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(
+ callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.listEnabledProviders(null, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ callbackCaptor.getValue().onResponse(response);
+
+ verify(callback).onResult(responseCaptor.capture());
+ assertThat(responseCaptor.getValue().getProviderComponentNames()).containsExactlyElementsIn(
+ response.getProviderComponentNames());
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullProviders() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(null, 0, mExecutor, response -> {
+ }));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, null, response -> {
+ }));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, mExecutor, null));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_failed() throws RemoteException {
+ OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ISetEnabledProvidersCallback.class);
+ ArgumentCaptor<SetEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass(
+ SetEnabledProvidersException.class);
+
+ final List<String> providers = List.of("foo", "bar");
+ final int userId = 0;
+ mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback);
+ verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0),
+ callbackCaptor.capture());
+
+ final String errorType = "unknown";
+ final String errorMessage = "Unknown error";
+ callbackCaptor.getValue().onError(errorType, errorMessage);
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
+ assertThat(errorCaptor.getValue().getMessage()).isEqualTo(errorMessage);
+ }
+
+ @Test
+ public void testSetEnabledProviders_success() throws RemoteException {
+ OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ISetEnabledProvidersCallback.class);
+
+ final List<String> providers = List.of("foo", "bar");
+ final int userId = 0;
+ mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0),
+ callbackCaptor.capture());
+
+ callbackCaptor.getValue().onResponse();
+ verify(callback).onResult(any());
+ }
+
+ @Test
+ public void testRegisterCredentialDescription_nullRequest() {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.registerCredentialDescription(null));
+ }
+
+ @Test
+ public void testRegisterCredentialDescription_success() throws RemoteException {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ mCredentialManager.registerCredentialDescription(mRegisterRequest);
+ verify(mMockCredentialManagerService).registerCredentialDescription(same(mRegisterRequest),
+ eq(mPackageName));
+ }
+
+ @Test
+ public void testUnregisterCredentialDescription_nullRequest() {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.unregisterCredentialDescription(null));
+ }
+
+ @Test
+ public void testUnregisterCredentialDescription_success() throws RemoteException {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ mCredentialManager.unregisterCredentialDescription(mUnregisterRequest);
+ verify(mMockCredentialManagerService).unregisterCredentialDescription(
+ same(mUnregisterRequest), eq(mPackageName));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 0d7c8b8..6d635af 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -58,7 +58,7 @@
// The number of flags held in boolean properties. Their values should also be double-checked
// in the methods above.
- private static final int NUM_BOOLEAN_PROPERTIES = 25;
+ private static final int NUM_BOOLEAN_PROPERTIES = 26;
@Test
public void testStandardActions_serializationFlagIsValid() {
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a37cb80..9ebcc75 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -281,6 +281,7 @@
<permission name="android.permission.MANAGE_GAME_MODE"/>
<permission name="android.permission.MANAGE_GAME_ACTIVITY" />
<permission name="android.permission.MANAGE_LOW_POWER_STANDBY" />
+ <permission name="android.permission.SET_LOW_POWER_STANDBY_PORTS" />
<permission name="android.permission.MANAGE_ROLLBACKS"/>
<permission name="android.permission.MANAGE_USB"/>
<!-- Needed for tests only -->
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b1abc2a1..a39dd08 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2175,23 +2175,26 @@
public static final @NonNull Parcelable.Creator<Bitmap> CREATOR
= new Parcelable.Creator<Bitmap>() {
- /**
- * Rebuilds a bitmap previously stored with writeToParcel().
- *
- * @param p Parcel object to read the bitmap from
- * @return a new bitmap created from the data in the parcel
- */
- public Bitmap createFromParcel(Parcel p) {
- Bitmap bm = nativeCreateFromParcel(p);
- if (bm == null) {
- throw new RuntimeException("Failed to unparcel Bitmap");
- }
- return bm;
- }
- public Bitmap[] newArray(int size) {
- return new Bitmap[size];
- }
- };
+ /**
+ * Rebuilds a bitmap previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the bitmap from
+ * @return a new bitmap created from the data in the parcel
+ */
+ public Bitmap createFromParcel(Parcel p) {
+ Bitmap bm = nativeCreateFromParcel(p);
+ if (bm == null) {
+ throw new RuntimeException("Failed to unparcel Bitmap");
+ }
+ if (p.readBoolean()) {
+ bm.setGainmap(p.readTypedObject(Gainmap.CREATOR));
+ }
+ return bm;
+ }
+ public Bitmap[] newArray(int size) {
+ return new Bitmap[size];
+ }
+ };
/**
* No special parcel contents.
@@ -2215,6 +2218,12 @@
if (!nativeWriteToParcel(mNativePtr, mDensity, p)) {
throw new RuntimeException("native writeToParcel failed");
}
+ if (hasGainmap()) {
+ p.writeBoolean(true);
+ p.writeTypedObject(mGainmap, flags);
+ } else {
+ p.writeBoolean(false);
+ }
}
/**
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index 53f23c0..470a06c 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -18,6 +18,8 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
import libcore.util.NativeAllocationRegistry;
@@ -76,7 +78,7 @@
*
* In the above math, log() is a natural logarithm and exp() is natural exponentiation.
*/
-public final class Gainmap {
+public final class Gainmap implements Parcelable {
// Use a Holder to allow static initialization of Gainmap in the boot image.
private static class NoImagePreloadHolder {
@@ -284,6 +286,50 @@
return nGetDisplayRatioSdr(mNativePtr);
}
+ /**
+ * No special parcel contents.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write the gainmap to the parcel.
+ *
+ * @param dest Parcel object to write the gainmap data into
+ * @param flags Additional flags about how the object should be written.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("Cannot be written to a parcel");
+ }
+ dest.writeTypedObject(mGainmapContents, flags);
+ // write gainmapinfo into parcel
+ nWriteGainmapToParcel(mNativePtr, dest);
+ }
+
+ public static final @NonNull Parcelable.Creator<Gainmap> CREATOR =
+ new Parcelable.Creator<Gainmap>() {
+ /**
+ * Rebuilds a gainmap previously stored with writeToParcel().
+ *
+ * @param in Parcel object to read the gainmap from
+ * @return a new gainmap created from the data in the parcel
+ */
+ public Gainmap createFromParcel(Parcel in) {
+ Gainmap gm = new Gainmap(in.readTypedObject(Bitmap.CREATOR));
+ // read gainmapinfo from parcel
+ nReadGainmapFromParcel(gm.mNativePtr, in);
+ return gm;
+ }
+
+ public Gainmap[] newArray(int size) {
+ return new Gainmap[size];
+ }
+ };
+
private static native long nGetFinalizer();
private static native long nCreateEmpty();
@@ -309,4 +355,6 @@
private static native void nSetDisplayRatioSdr(long ptr, float min);
private static native float nGetDisplayRatioSdr(long ptr);
+ private static native void nWriteGainmapToParcel(long ptr, Parcel dest);
+ private static native void nReadGainmapFromParcel(long ptr, Parcel src);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index bc81710..c9c0e40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -41,6 +41,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.DisplayAreaInfo;
@@ -363,10 +364,10 @@
}
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);
- WindowContainerTransaction wct = mTransitions.dispatchRequest(transition, request, this);
- if (wct == null) {
- wct = new WindowContainerTransaction();
- }
+ Pair<Transitions.TransitionHandler, WindowContainerTransaction> subHandler =
+ mTransitions.dispatchRequest(transition, request, this);
+ WindowContainerTransaction wct = subHandler != null
+ ? subHandler.second : new WindowContainerTransaction();
bringDesktopAppsToFront(wct);
wct.reorder(request.getTriggerTask().token, true /* onTop */);
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 a2d7bc4..c2da705 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
@@ -17,6 +17,7 @@
package com.android.wm.shell.transition;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -28,11 +29,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.pip.PipTransitionController;
@@ -61,6 +64,9 @@
/** Both the display and split-state (enter/exit) is changing */
static final int TYPE_DISPLAY_AND_SPLIT_CHANGE = 2;
+ /** Pip was entered while handling an intent with its own remoteTransition. */
+ static final int TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE = 3;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -85,6 +91,23 @@
mType = type;
mTransition = transition;
}
+
+ void joinFinishArgs(WindowContainerTransaction wct,
+ WindowContainerTransactionCallback wctCB) {
+ if (wctCB != null) {
+ // Technically can probably support 1, but don't want to encourage CB usage since
+ // it creates instabliity, so just throw.
+ throw new IllegalArgumentException("Can't mix transitions that require finish"
+ + " sync callback");
+ }
+ if (wct != null) {
+ if (mFinishWCT == null) {
+ mFinishWCT = wct;
+ } else {
+ mFinishWCT.merge(wct, true /* transfer */);
+ }
+ }
+ }
}
private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
@@ -125,6 +148,25 @@
mPipHandler.augmentRequest(transition, request, out);
mSplitHandler.addEnterOrExitIfNeeded(request, out);
return out;
+ } else if (request.getRemoteTransition() != null
+ && Transitions.isOpeningType(request.getType())
+ && (request.getTriggerTask() == null
+ || (request.getTriggerTask().topActivityType != ACTIVITY_TYPE_HOME
+ && request.getTriggerTask().topActivityType != ACTIVITY_TYPE_RECENTS))) {
+ // Only select transitions with an intent-provided remote-animation because that will
+ // usually grab priority and often won't handle PiP. If there isn't an intent-provided
+ // remote, then the transition will be dispatched normally and the PipHandler will
+ // pick it up.
+ Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler =
+ mPlayer.dispatchRequest(transition, request, this);
+ if (handler == null) {
+ return null;
+ }
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE, transition);
+ mixed.mLeftoversHandler = handler.first;
+ mActiveTransitions.add(mixed);
+ return handler.second;
}
return null;
}
@@ -169,6 +211,9 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) {
return false;
+ } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
+ return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction,
+ finishTransaction, finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -176,6 +221,59 @@
}
}
+ private boolean animateOpenIntentWithRemoteAndPip(@NonNull MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ TransitionInfo.Change pipChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (mPipHandler.isEnteringPip(change, info.getType())) {
+ if (pipChange != null) {
+ throw new IllegalStateException("More than 1 pip-entering changes in one"
+ + " transition? " + info);
+ }
+ pipChange = change;
+ info.getChanges().remove(i);
+ }
+ }
+ if (pipChange == null) {
+ if (mixed.mLeftoversHandler != null) {
+ return mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCallback);
+ }
+ return false;
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Splitting PIP into a separate"
+ + " animation because remote-animation likely doesn't support it");
+ mixed.mFinishCallback = finishCallback;
+ Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ --mixed.mInFlightSubAnimations;
+ mixed.joinFinishArgs(wct, wctCB);
+ if (mixed.mInFlightSubAnimations > 0) return;
+ mActiveTransitions.remove(mixed);
+ mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ };
+ // Split the transition into 2 parts: the pip part and the rest.
+ mixed.mInFlightSubAnimations = 2;
+ // make a new startTransaction because pip's startEnterAnimation "consumes" it so
+ // we need a separate one to send over to launcher.
+ SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
+
+ mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, finishCB);
+
+ // Dispatch the rest of the transition normally.
+ if (mixed.mLeftoversHandler != null
+ && mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCB)) {
+ return true;
+ }
+ mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCB, this);
+ return true;
+ }
+
private boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed,
@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -211,12 +309,13 @@
mixed.mFinishCallback = finishCallback;
Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
--mixed.mInFlightSubAnimations;
+ mixed.joinFinishArgs(wct, wctCB);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
if (isGoingHome) {
mSplitHandler.onTransitionAnimationComplete();
}
- mixed.mFinishCallback.onTransitionFinished(wct, wctCB);
+ mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
};
if (isGoingHome) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
@@ -317,17 +416,7 @@
Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
--mixed.mInFlightSubAnimations;
- if (wctCB != null) {
- throw new IllegalArgumentException("Can't mix transitions that require finish"
- + " sync callback");
- }
- if (wct != null) {
- if (mixed.mFinishWCT == null) {
- mixed.mFinishWCT = wct;
- } else {
- mixed.mFinishWCT.merge(wct, true /* transfer */);
- }
- }
+ mixed.joinFinishArgs(wct, wctCB);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */);
@@ -342,8 +431,7 @@
// Note: at this point, startT has probably already been applied, so we are basically
// giving splitHandler an empty startT. This is currently OK because display-change will
// grab a screenshot and paste it on top anyways.
- mSplitHandler.startPendingAnimation(
- transition, everythingElse, startT, finishT, finishCB);
+ mSplitHandler.startPendingAnimation(transition, everythingElse, startT, finishT, finishCB);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 75d1939..0826fe2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -47,6 +47,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITransitionPlayer;
@@ -627,13 +628,14 @@
* Gives every handler (in order) a chance to handle request until one consumes the transition.
* @return the WindowContainerTransaction given by the handler which consumed the transition.
*/
- public WindowContainerTransaction dispatchRequest(@NonNull IBinder transition,
- @NonNull TransitionRequestInfo request, @Nullable TransitionHandler skip) {
+ public Pair<TransitionHandler, WindowContainerTransaction> dispatchRequest(
+ @NonNull IBinder transition, @NonNull TransitionRequestInfo request,
+ @Nullable TransitionHandler skip) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
if (mHandlers.get(i) == skip) continue;
WindowContainerTransaction wct = mHandlers.get(i).handleRequest(transition, request);
if (wct != null) {
- return wct;
+ return new Pair<>(mHandlers.get(i), wct);
}
}
return null;
@@ -698,9 +700,9 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"Transition animation finished (abort=%b), notifying core %s", abort, transition);
if (active.mStartT != null) {
- // Applied by now, so close immediately. Do not set to null yet, though, since nullness
- // is used later to disambiguate malformed transitions.
- active.mStartT.close();
+ // Applied by now, so clear immediately to remove any references. Do not set to null
+ // yet, though, since nullness is used later to disambiguate malformed transitions.
+ active.mStartT.clear();
}
// Merge all relevant transactions together
SurfaceControl.Transaction fullFinish = active.mFinishT;
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 44e4a31..de5f2f4 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
@@ -250,25 +250,30 @@
@Override
public boolean onTouch(View v, MotionEvent e) {
- boolean isDrag = false;
final int id = v.getId();
if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) {
return false;
}
- if (id == R.id.caption_handle) {
- isDrag = mDragDetector.onMotionEvent(e);
+ switch (e.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragDetector.onMotionEvent(e);
+ final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ if (taskInfo.isFocused) {
+ return mDragDetector.isDragEvent();
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reorder(mTaskToken, true /* onTop */);
+ mSyncQueue.queue(wct);
+ return false;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ boolean res = mDragDetector.isDragEvent();
+ mDragDetector.onMotionEvent(e);
+ return res;
+ default:
+ mDragDetector.onMotionEvent(e);
+ return mDragDetector.isDragEvent();
}
- if (e.getAction() != MotionEvent.ACTION_DOWN) {
- return isDrag;
- }
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
- if (taskInfo.isFocused) {
- return isDrag;
- }
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reorder(mTaskToken, true /* onTop */);
- mSyncQueue.queue(wct);
- return true;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 4fac843..cf1850b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -94,6 +94,10 @@
mTouchSlop = touchSlop;
}
+ boolean isDragEvent() {
+ return mIsDragEvent;
+ }
+
private void resetState() {
mIsDragEvent = false;
mInputDownPoint.set(0, 0);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 03d89cc..d63b3e7 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -364,6 +364,7 @@
"jni/PathMeasure.cpp",
"jni/Picture.cpp",
"jni/Region.cpp",
+ "jni/ScopedParcel.cpp",
"jni/Shader.cpp",
"jni/RenderEffect.cpp",
"jni/Typeface.cpp",
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index e71a2a5..3f9c4bd 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -10,6 +10,7 @@
#include "Gainmap.h"
#include "GraphicsJNI.h"
#include "HardwareBufferHelpers.h"
+#include "ScopedParcel.h"
#include "SkBitmap.h"
#include "SkBlendMode.h"
#include "SkCanvas.h"
@@ -27,12 +28,7 @@
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
#include <android-base/unique_fd.h>
-#include <android/binder_parcel.h>
-#include <android/binder_parcel_jni.h>
-#include <android/binder_parcel_platform.h>
-#include <cutils/ashmem.h>
#include <renderthread/RenderProxy.h>
-#include <sys/mman.h>
#endif
#include <inttypes.h>
@@ -616,91 +612,7 @@
///////////////////////////////////////////////////////////////////////////////
// TODO: Move somewhere else
-#ifdef __ANDROID__ // Layoutlib does not support parcel
-
-class ScopedParcel {
-public:
- explicit ScopedParcel(JNIEnv* env, jobject parcel) {
- mParcel = AParcel_fromJavaParcel(env, parcel);
- }
-
- ~ScopedParcel() { AParcel_delete(mParcel); }
-
- int32_t readInt32() {
- int32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- uint32_t readUint32() {
- uint32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
-
- void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
-
- bool allowFds() const { return AParcel_getAllowFds(mParcel); }
-
- std::optional<sk_sp<SkData>> readData() {
- struct Data {
- void* ptr = nullptr;
- size_t size = 0;
- } data;
- auto error = AParcel_readByteArray(mParcel, &data,
- [](void* arrayData, int32_t length,
- int8_t** outBuffer) -> bool {
- Data* data = reinterpret_cast<Data*>(arrayData);
- if (length > 0) {
- data->ptr = sk_malloc_canfail(length);
- if (!data->ptr) {
- return false;
- }
- *outBuffer =
- reinterpret_cast<int8_t*>(data->ptr);
- data->size = length;
- }
- return true;
- });
- if (error != STATUS_OK || data.size <= 0) {
- sk_free(data.ptr);
- return std::nullopt;
- } else {
- return SkData::MakeFromMalloc(data.ptr, data.size);
- }
- }
-
- void writeData(const std::optional<sk_sp<SkData>>& optData) {
- if (optData) {
- const auto& data = *optData;
- AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
- data->size());
- } else {
- AParcel_writeByteArray(mParcel, nullptr, -1);
- }
- }
-
- AParcel* get() { return mParcel; }
-
-private:
- AParcel* mParcel;
-};
-
-enum class BlobType : int32_t {
- IN_PLACE,
- ASHMEM,
-};
-
+#ifdef __ANDROID__ // Layoutlib does not support parcel
#define ON_ERROR_RETURN(X) \
if ((error = (X)) != STATUS_OK) return error
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index 9cd3fb0..0f8a85d 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -16,8 +16,13 @@
#include <Gainmap.h>
+#ifdef __ANDROID__
+#include <binder/Parcel.h>
+#endif
+
#include "Bitmap.h"
#include "GraphicsJNI.h"
+#include "ScopedParcel.h"
#include "graphics_jni_helpers.h"
namespace android {
@@ -154,6 +159,81 @@
return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
}
+// ----------------------------------------------------------------------------
+// Serialization
+// ----------------------------------------------------------------------------
+
+static void Gainmap_writeToParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+ if (parcel == NULL) {
+ ALOGD("write null parcel\n");
+ return;
+ }
+ ScopedParcel p(env, parcel);
+ SkGainmapInfo info = fromJava(nativeObject)->info;
+ // write gainmap to parcel
+ // ratio min
+ p.writeFloat(info.fGainmapRatioMin.fR);
+ p.writeFloat(info.fGainmapRatioMin.fG);
+ p.writeFloat(info.fGainmapRatioMin.fB);
+ // ratio max
+ p.writeFloat(info.fGainmapRatioMax.fR);
+ p.writeFloat(info.fGainmapRatioMax.fG);
+ p.writeFloat(info.fGainmapRatioMax.fB);
+ // gamma
+ p.writeFloat(info.fGainmapGamma.fR);
+ p.writeFloat(info.fGainmapGamma.fG);
+ p.writeFloat(info.fGainmapGamma.fB);
+ // epsilonsdr
+ p.writeFloat(info.fEpsilonSdr.fR);
+ p.writeFloat(info.fEpsilonSdr.fG);
+ p.writeFloat(info.fEpsilonSdr.fB);
+ // epsilonhdr
+ p.writeFloat(info.fEpsilonHdr.fR);
+ p.writeFloat(info.fEpsilonHdr.fG);
+ p.writeFloat(info.fEpsilonHdr.fB);
+ // display ratio sdr
+ p.writeFloat(info.fDisplayRatioSdr);
+ // display ratio hdr
+ p.writeFloat(info.fDisplayRatioHdr);
+ // base image type
+ p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
+ // type
+ p.writeInt32(static_cast<int32_t>(info.fType));
+#else
+ doThrowRE(env, "Cannot use parcels outside of Android!");
+#endif
+}
+
+static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+ if (parcel == NULL) {
+ jniThrowNullPointerException(env, "parcel cannot be null");
+ return;
+ }
+ ScopedParcel p(env, parcel);
+
+ SkGainmapInfo info;
+ info.fGainmapRatioMin = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fGainmapRatioMax = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fGainmapGamma = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fEpsilonSdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fEpsilonHdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fDisplayRatioSdr = p.readFloat();
+ info.fDisplayRatioHdr = p.readFloat();
+ info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
+ info.fType = static_cast<SkGainmapInfo::Type>(p.readInt32());
+
+ fromJava(nativeObject)->info = info;
+#else
+ jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
static const JNINativeMethod gGainmapMethods[] = {
{"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
{"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
@@ -172,6 +252,8 @@
{"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
{"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
{"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
+ {"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
+ {"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
};
int register_android_graphics_Gainmap(JNIEnv* env) {
diff --git a/libs/hwui/jni/ScopedParcel.cpp b/libs/hwui/jni/ScopedParcel.cpp
new file mode 100644
index 0000000..b0f5423
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.cpp
@@ -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.
+ */
+#include "ScopedParcel.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+
+using namespace android;
+
+int32_t ScopedParcel::readInt32() {
+ int32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+uint32_t ScopedParcel::readUint32() {
+ uint32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+float ScopedParcel::readFloat() {
+ float temp = 0.;
+ if (AParcel_readFloat(mParcel, &temp) != STATUS_OK) {
+ temp = 0.;
+ }
+ return temp;
+}
+
+std::optional<sk_sp<SkData>> ScopedParcel::readData() {
+ struct Data {
+ void* ptr = nullptr;
+ size_t size = 0;
+ } data;
+ auto error = AParcel_readByteArray(
+ mParcel, &data, [](void* arrayData, int32_t length, int8_t** outBuffer) -> bool {
+ Data* data = reinterpret_cast<Data*>(arrayData);
+ if (length > 0) {
+ data->ptr = sk_malloc_canfail(length);
+ if (!data->ptr) {
+ return false;
+ }
+ *outBuffer = reinterpret_cast<int8_t*>(data->ptr);
+ data->size = length;
+ }
+ return true;
+ });
+ if (error != STATUS_OK || data.size <= 0) {
+ sk_free(data.ptr);
+ return std::nullopt;
+ } else {
+ return SkData::MakeFromMalloc(data.ptr, data.size);
+ }
+}
+
+void ScopedParcel::writeData(const std::optional<sk_sp<SkData>>& optData) {
+ if (optData) {
+ const auto& data = *optData;
+ AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
+ data->size());
+ } else {
+ AParcel_writeByteArray(mParcel, nullptr, -1);
+ }
+}
+#endif // __ANDROID__ // Layoutlib does not support parcel
diff --git a/libs/hwui/jni/ScopedParcel.h b/libs/hwui/jni/ScopedParcel.h
new file mode 100644
index 0000000..fd8d6a2
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+#include "SkData.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+#include <android-base/unique_fd.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_jni.h>
+#include <android/binder_parcel_platform.h>
+#include <cutils/ashmem.h>
+#include <renderthread/RenderProxy.h>
+
+class ScopedParcel {
+public:
+ explicit ScopedParcel(JNIEnv* env, jobject parcel) {
+ mParcel = AParcel_fromJavaParcel(env, parcel);
+ }
+
+ ~ScopedParcel() { AParcel_delete(mParcel); }
+
+ int32_t readInt32();
+
+ uint32_t readUint32();
+
+ float readFloat();
+
+ void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
+
+ void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
+
+ void writeFloat(float value) { AParcel_writeFloat(mParcel, value); }
+
+ bool allowFds() const { return AParcel_getAllowFds(mParcel); }
+
+ std::optional<sk_sp<SkData>> readData();
+
+ void writeData(const std::optional<sk_sp<SkData>>& optData);
+
+ AParcel* get() { return mParcel; }
+
+private:
+ AParcel* mParcel;
+};
+
+enum class BlobType : int32_t {
+ IN_PLACE,
+ ASHMEM,
+};
+
+#endif // __ANDROID__ // Layoutlib does not support parcel
\ No newline at end of file
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 076e0cb..52dfb66 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -681,6 +681,20 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Flags {}
+ /** @hide */
+ @IntDef(flag = true, prefix = "FLAG", value = {
+ FLAG_SHOW_UI,
+ FLAG_ALLOW_RINGER_MODES,
+ FLAG_PLAY_SOUND,
+ FLAG_REMOVE_SOUND_AND_VIBRATE,
+ FLAG_VIBRATE,
+ FLAG_BLUETOOTH_ABS_VOLUME,
+ FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
+ FLAG_FROM_KEY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SystemVolumeFlags {}
+
// The iterator of TreeMap#entrySet() returns the entries in ascending key order.
private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
@@ -1445,7 +1459,7 @@
android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS,
android.Manifest.permission.MODIFY_AUDIO_ROUTING
})
- public void setVolumeGroupVolumeIndex(int groupId, int index, int flags) {
+ public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) {
final IAudioService service = getService();
try {
service.setVolumeGroupVolumeIndex(groupId, index, flags,
@@ -1542,7 +1556,7 @@
* @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
* is not granted notification policy access.
*/
- public void adjustVolumeGroupVolume(int groupId, int direction, int flags) {
+ public void adjustVolumeGroupVolume(int groupId, int direction, @SystemVolumeFlags int flags) {
IAudioService service = getService();
try {
service.adjustVolumeGroupVolume(groupId, direction, flags,
@@ -1564,10 +1578,10 @@
@SystemApi
@RequiresPermission("android.permission.QUERY_AUDIO_STATE")
@IntRange(from = 0)
- public int getLastAudibleVolumeGroupVolume(int groupId) {
+ public int getLastAudibleVolumeForVolumeGroup(int groupId) {
IAudioService service = getService();
try {
- return service.getLastAudibleVolumeGroupVolume(groupId);
+ return service.getLastAudibleVolumeForVolumeGroup(groupId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 324e81a..4808692 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -153,7 +153,7 @@
int getVolumeGroupMinVolumeIndex(int groupId);
@EnforcePermission("QUERY_AUDIO_STATE")
- int getLastAudibleVolumeGroupVolume(int groupId);
+ int getLastAudibleVolumeForVolumeGroup(int groupId);
boolean isVolumeGroupMuted(int groupId);
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 7ef0f77..9a6d5d7 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -30,7 +30,6 @@
#include <camera/Camera.h>
#include <media/mediarecorder.h>
#include <media/MediaMetricsItem.h>
-#include <media/MicrophoneInfo.h>
#include <media/stagefright/PersistentSurface.h>
#include <utils/threads.h>
@@ -774,7 +773,7 @@
}
jint jStatus = AUDIO_JAVA_SUCCESS;
- std::vector<media::MicrophoneInfo> activeMicrophones;
+ std::vector<media::MicrophoneInfoFw> activeMicrophones;
status_t status = mr->getActiveMicrophones(&activeMicrophones);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "MediaRecorder::getActiveMicrophones error %d", status);
diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml
index 499d130..b36cb5c 100644
--- a/packages/CredentialManager/AndroidManifest.xml
+++ b/packages/CredentialManager/AndroidManifest.xml
@@ -35,6 +35,7 @@
<activity
android:name=".CredentialSelectorActivity"
android:exported="true"
+ android:permission="android.permission.LAUNCH_CREDENTIAL_SELECTOR"
android:launchMode="singleTop"
android:label="@string/app_name"
android:excludeFromRecents="true"
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 9eda82a..3eb58f1 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -92,8 +92,8 @@
<string name="close_sheet">"Close sheet"</string>
<!-- Spoken content description of the back arrow button. -->
<string name="accessibility_back_arrow_button">"Go back to the previous page"</string>
- <!-- Spoken content description of the close button. -->
- <string name="accessibility_close_button">"Close the Credential Manager action suggestion appearing at the bottom of the screen"</string>
+ <!-- Spoken content description of the close "X" icon button. -->
+ <string name="accessibility_close_button">Close</string>
<!-- Strings for the get flow. -->
<!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
@@ -120,6 +120,8 @@
<string name="locked_credential_entry_label_subtext_tap_to_unlock">Tap to unlock</string>
<!-- Explanatory label for a disabled button explaining that this option isn't viable because it does not contain any available credential (e.g. password, passkey, etc.) for the user. [CHAR LIMIT=120] -->
<string name="locked_credential_entry_label_subtext_no_sign_in">No sign-in info</string>
+ <!-- Label displayed when a selected option does not contain any viable credentials that can be used to log into the app. [CHAR LIMIT=80] -->
+ <string name="no_sign_in_info_in">No sign-in info in <xliff:g id="source" example="becket@gmail.com">%1$s</xliff:g></string>
<!-- Column heading for displaying action chips for managing sign-ins from each credential provider. [CHAR LIMIT=80] -->
<string name="get_dialog_heading_manage_sign_ins">Manage sign-ins</string>
<!-- Column heading for displaying option to use sign-ins saved on a different device. [CHAR LIMIT=80] -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 30b4b86..f57d643 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -115,6 +115,11 @@
}
}
+ fun onLastLockedAuthEntryNotFoundError() {
+ Log.d(Constants.LOG_TAG, "Unable to find the last unlocked entry")
+ onInternalError()
+ }
+
private fun onInternalError() {
Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
credManRepo.onParsingFailureCancel()
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 438978c..dc9bdec 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -79,7 +79,20 @@
getCredentialUiState: GetCredentialUiState,
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
- if (getCredentialUiState.currentScreenState != GetScreenState.REMOTE_ONLY) {
+ if (getCredentialUiState.currentScreenState == GetScreenState.REMOTE_ONLY) {
+ RemoteCredentialSnackBarScreen(
+ onClick = viewModel::getFlowOnMoreOptionOnSnackBarSelected,
+ onCancel = viewModel::onCancel,
+ )
+ } else if (getCredentialUiState.currentScreenState
+ == GetScreenState.UNLOCKED_AUTH_ENTRIES_ONLY) {
+ EmptyAuthEntrySnackBarScreen(
+ authenticationEntryList =
+ getCredentialUiState.providerDisplayInfo.authenticationEntryList,
+ onCancel = viewModel::onCancel,
+ onLastLokcedAuthEntryNotFound = viewModel::onLastLockedAuthEntryNotFoundError,
+ )
+ } else {
ModalBottomSheet(
sheetContent = {
// Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
@@ -124,11 +137,6 @@
},
onDismiss = viewModel::onCancel,
)
- } else {
- SnackBarScreen(
- onClick = viewModel::getFlowOnMoreOptionOnSnackBarSelected,
- onCancel = viewModel::onCancel,
- )
}
}
@@ -622,7 +630,7 @@
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun SnackBarScreen(
+fun RemoteCredentialSnackBarScreen(
onClick: (Boolean) -> Unit,
onCancel: () -> Unit,
) {
@@ -653,4 +661,37 @@
) {
Text(text = stringResource(R.string.get_dialog_use_saved_passkey_for))
}
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun EmptyAuthEntrySnackBarScreen(
+ authenticationEntryList: List<AuthenticationEntryInfo>,
+ onCancel: () -> Unit,
+ onLastLokcedAuthEntryNotFound: () -> Unit,
+) {
+ val lastLocked = authenticationEntryList.firstOrNull({it.isLastUnlocked})
+ if (lastLocked == null) {
+ onLastLokcedAuthEntryNotFound()
+ return
+ }
+
+ // TODO: Change the height, width and position according to the design
+ Snackbar(
+ modifier = Modifier.padding(horizontal = 40.dp).padding(top = 700.dp),
+ shape = EntryShape.FullMediumRoundedCorner,
+ containerColor = LocalAndroidColorScheme.current.colorBackground,
+ contentColor = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+ dismissAction = {
+ IconButton(onClick = onCancel) {
+ Icon(
+ Icons.Filled.Close,
+ contentDescription = stringResource(R.string.accessibility_close_button),
+ tint = LocalAndroidColorScheme.current.colorAccentTertiary
+ )
+ }
+ },
+ ) {
+ Text(text = stringResource(R.string.no_sign_in_info_in, lastLocked.title))
+ }
}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index d04f926..49415c0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -28,8 +28,8 @@
data class GetCredentialUiState(
val providerInfoList: List<ProviderInfo>,
val requestDisplayInfo: RequestDisplayInfo,
- val currentScreenState: GetScreenState = toGetScreenState(providerInfoList),
val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
+ val currentScreenState: GetScreenState = toGetScreenState(providerDisplayInfo),
val activeEntry: BaseEntry? = toActiveEntry(providerDisplayInfo),
val isNoAccount: Boolean = false,
)
@@ -167,6 +167,9 @@
/** The snackbar only page when there's no account but only a remoteEntry. */
REMOTE_ONLY,
+
+ /** The snackbar when there are only auth entries and all of them turn out to be empty. */
+ UNLOCKED_AUTH_ENTRIES_ONLY,
}
// IMPORTANT: new invocation should be mindful that this method will throw if more than 1 remote
@@ -174,7 +177,6 @@
private fun toProviderDisplayInfo(
providerInfoList: List<ProviderInfo>
): ProviderDisplayInfo {
-
val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
val remoteEntryList = mutableListOf<RemoteEntryInfo>()
@@ -241,22 +243,18 @@
}
private fun toGetScreenState(
- providerInfoList: List<ProviderInfo>
+ providerDisplayInfo: ProviderDisplayInfo
): GetScreenState {
- var noLocalAccount = true
- var remoteInfo: RemoteEntryInfo? = null
- providerInfoList.forEach { providerInfo ->
- if (providerInfo.credentialEntryList.isNotEmpty() ||
- providerInfo.authenticationEntryList.isNotEmpty()) {
- noLocalAccount = false
- }
- if (providerInfo.remoteEntry != null) {
- remoteInfo = providerInfo.remoteEntry
- }
- }
- return if (noLocalAccount && remoteInfo != null)
- GetScreenState.REMOTE_ONLY else GetScreenState.PRIMARY_SELECTION
+ return if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() &&
+ providerDisplayInfo.remoteEntry == null &&
+ providerDisplayInfo.authenticationEntryList.all { it.isUnlockedAndEmpty })
+ GetScreenState.UNLOCKED_AUTH_ENTRIES_ONLY
+ else if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() &&
+ providerDisplayInfo.authenticationEntryList.isEmpty() &&
+ providerDisplayInfo.remoteEntry != null)
+ GetScreenState.REMOTE_ONLY
+ else GetScreenState.PRIMARY_SELECTION
}
internal class CredentialEntryInfoComparatorByTypeThenTimestamp : Comparator<CredentialEntryInfo> {
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index a7e44d3..006c9c1 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Het gefiltreer geaktiveer"</item>
<item msgid="2779123106632690576">"Geaktiveer"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (verstek)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index b1f2cee..31f50e8 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Hierdie foon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Hierdie tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan nie op hierdie toestel speel nie"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Gradeer rekening op om oor te skakel"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan nie aflaaie hier speel nie"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Probeer weer ná die advertensie"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Maak toestel wakker om hier te speel"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Toestel is nie goedgekeur om te speel nie"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan nie hierdie media hier speel nie"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 7bef7fa..43c89b1 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ማጣሪያን አንቃ"</item>
<item msgid="2779123106632690576">"ነቅቷል"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ነባሪ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index cf4b62d..b9117ee 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ይህ ስልክ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ይህ ጡባዊ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"በዚህ መሣሪያ ላይ ማጫወት አልተቻለም"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ለመቀየር መለያ ያልቁ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ውርዶችን እዚህ ማጫወት አይቻልም"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ከማስታወቂያው በኋላ እንደገና ይሞክሩ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"እዚህ ጋር ለመጫወት መሣሪያን ያንቁ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"መሣሪያ ለማጫወት አልጸደቀም"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ይህን ሚዲያ እዚህ ጋር ማጫወት አይቻልም"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
<string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 0720cf5..1a16f5a 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"تمّ تفعيل التصفية"</item>
<item msgid="2779123106632690576">"مفعّل"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (تلقائي)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 1b4b521..ef7bf08 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"هذا الهاتف"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"هذا الجهاز اللوحي"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"لا يمكن تشغيل الوسائط على هذا الجهاز."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"يجب ترقية الحساب للتبديل."</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"لا يمكن تشغيل المحتوى الذي تم تنزيله هنا."</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"يمكنك إعادة المحاولة بعد الإعلان."</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"يجب تنشيط الجهاز لتشغيل الوسائط هنا."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"غير مسموح لهذا الجهاز بتشغيل الوسائط."</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"لا يمكن تشغيل هذه الوسائط هنا."</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
<string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات"</string>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index cbacce8..456fa3d 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"সক্ষম কৰাবিলাক ফিল্টাৰ কৰা হৈছে"</item>
<item msgid="2779123106632690576">"সক্ষম কৰা আছে"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ডিফ’ল্ট)"</item>
<item msgid="1637054408779685086">"AVRCP ১.৩"</item>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 454c6ed..67b18da 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফ’নটো"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"এই টেবলেটটো"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"এই ডিভাইচটো প্লে\' কৰিব নোৱাৰি"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"সলনি কৰিবলৈ একাউণ্ট আপগ্ৰে’ড কৰক"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ইয়াত ডাউনল’ডসমূহ প্লে’ কৰিব নোৱাৰি"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"বিজ্ঞাপনটোৰ পাছত পুনৰ চেষ্টা কৰক"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ইয়াত প্লে\' কৰিবলৈ ডিভাইচটো সক্ৰিয় কৰক"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"প্লে\' কৰিবলৈ ডিভাইচটো অনুমোদিত নহয়"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ইয়াত এই মিডিয়াটো প্লে\' কৰিব নোৱাৰি"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
<string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index d1f157a..dacaaca 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrləmə aktivdir"</item>
<item msgid="2779123106632690576">"Aktivdir"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Defolt)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index fa7af3b..000fd1b 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu planşet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oxutmaq mümkün deyil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Keçirmək üçün hesabı təkmilləşdirin"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Burada endirmələri oxutmaq mümkün deyil"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Reklamdan sonra yenidən cəhd edin"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Burada oxutmaq üçün cihazı oyadın"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Cihaz oxudulmaq üçün təsdiqlənməyib"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Bu medianı burada oxutmaq mümkün deyil"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 63b08fa..8e6fae6 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Omogućeno filtrirano"</item>
<item msgid="2779123106632690576">"Omogućeno"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (podrazumevano)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ef74b68..6a9ba8a 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ne možete da pustite na ovom uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite nalog radi prebacivanja"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Preuzimanja ne mogu da se puštaju ovde"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Probajte ponovo posle oglasa"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Probudite uređaj da biste pustili ovde"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Uređaj nije odobren za reprodukciju"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ne možete da pustite ovaj medijski fajl ovde"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index f16e1c5..ced9acf 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Уключана з фільтрацыяй"</item>
<item msgid="2779123106632690576">"Уключана"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (стандартная)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 0c75f26..f93ca4b 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Гэты тэлефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Гэты планшэт"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не ўдаецца прайграць на гэтай прыладзе"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для пераключэння перайдзіце на іншую версію ўліковага запісу"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Тут не ўдаецца прайграць спампоўкі"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Паўтарыце спробу пасля рэкламы"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Для прайгравання на гэтай прыладзе абудзіце яе"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Для прайгравання на прыладзе патрабуецца ўхваленне"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Тут не ўдаецца прайграць мультымедыя"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
<string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 849e694..c129304 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Филтрирането е активирано"</item>
<item msgid="2779123106632690576">"Активирано"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (основно)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index cd5572a..650f405 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Този телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Този таблет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Възпроизвеждането не е възможно на това устройство"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надстройте профила, за да превключите"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Изтеглянията не могат да се възпроизвеждат тук"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Опитайте отново след рекламата"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Активирайте устройството, за да възпроизведете съдържанието тук"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Устройството не е одобрено да възпроизвежда съдържание"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Мултимедийното съдържание не може да се възпроизведе тук"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
<string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index a3bc4fd..d583738 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ফিল্টার করা চালু আছে"</item>
<item msgid="2779123106632690576">"চালু করা আছে"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ডিফল্ট)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 926ad84..c2e80b6 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Omogućeno filtrirano"</item>
<item msgid="2779123106632690576">"Omogućeno"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Filtrirana zaglavlja"</item>
+ <item msgid="4818549483446395865">"Filtrirani A2DP medijski paketi"</item>
+ <item msgid="8207123990453243311">"Filtrirani RFCOMM kanal"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Onemogućeno"</item>
+ <item msgid="5884245882825346396">"Čarolija"</item>
+ <item msgid="6569400572915342949">"Zaglavlje"</item>
+ <item msgid="1239386221416967664">"Potpuni filtar"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (zadano)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 574fa9d..e8cabfa 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nije moguće reproducirati na uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite račun da promijenite"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Nije moguće reproducirati preuzimanja ovdje"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Pokušajte ponovo nakon oglasa"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivirajte uređaj da reproducirate ovdje"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Uređaj nije odobren za reprodukciju"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Nije moguće ovdje reproducirati medij"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 3062e7d..20a3d03 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Activat amb filtres"</item>
<item msgid="2779123106632690576">"Activat"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predeterminada)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 0ccd82a..83b32d4 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Aquest telèfon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Aquesta tauleta"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"No es pot reproduir en aquest dispositiu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualitza el compte per canviar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Les baixades no es poden reproduir aquí"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Torna-ho a provar després de l\'anunci"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositiu per reproduir aquí"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"El dispositiu no està aprovat per reproduir contingut"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No es pot reproduir aquest contingut multimèdia aquí"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index e1d033c..ad6062c 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Povolit filtrované"</item>
<item msgid="2779123106632690576">"Zapnuto"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (výchozí)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index f2bf000..e511f04 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Na tomto zařízení média přehrávat nelze"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Pokud chcete přejít, upgradujte účet"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Stažený obsah zde nelze přehrát"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Zkuste to znovu po reklamě"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Pokud zde chcete přehrávat média, probuďte zařízení"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Zařízení není schváleno k přehrávání"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tato média zde přehrát nelze"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
<string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 48a33f6..6fc4714 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtreret er aktiveret"</item>
<item msgid="2779123106632690576">"Aktiveret"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 9671f5e..c52c661 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Denne tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Indholdet kan ikke afspilles på denne enhed"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Opgrader kontoen for at skifte"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Downloads kan ikke afspilles her"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Prøv igen efter annoncen"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Væk enheden for at afspille her"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheden er ikke godkendt til afspilning"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Mediet kan ikke afspilles her"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index ca999db..636a7a4 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filter aktiviert"</item>
<item msgid="2779123106632690576">"Aktiviert"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Standard)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9e77007..dd677c9 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -540,17 +540,13 @@
<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>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <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>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Downloads können hier nicht abgespielt werden"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Nach Werbung noch einmal versuchen"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Gerät aktivieren, um hier etwas wiedergeben zu lassen"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Gerät nicht für die Wiedergabe zugelassen"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Diese Medien können hier nicht wiedergegeben werden"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus & und wieder ein."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
<string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index b95f6fc..986adf5 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Ενεργοποιήθηκε το φιλτράρισμα"</item>
<item msgid="2779123106632690576">"Ενεργοποιήθηκε"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Προεπιλογή)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2ca882d..1e11424 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Αυτό το tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφωνο"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Δεν είναι δυνατή η αναπαραγωγή σε αυτήν τη συσκευή"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Αναβαθμίστε τον λογαριασμό για εναλλαγή"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Δεν είναι δυνατή η αναπαραγωγή των λήψεων εδώ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Δοκιμάστε ξανά μετά τη διαφήμιση"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Αφύπνιση συσκευής για αναπαραγωγή εδώ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Η συσκευή δεν έχει εγκριθεί για αναπαραγωγή"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Δεν είναι δυνατή η αναπαραγωγή αυτού του πολυμέσου εδώ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
<string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 327e4e9..de63386 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Enabled Filtered"</item>
<item msgid="2779123106632690576">"Enabled"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Headers filtered"</item>
+ <item msgid="4818549483446395865">"A2DP media packets filtered"</item>
+ <item msgid="8207123990453243311">"RFCOMM channel filtered"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Disabled"</item>
+ <item msgid="5884245882825346396">"Magic"</item>
+ <item msgid="6569400572915342949">"Header"</item>
+ <item msgid="1239386221416967664">"Full filter"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index 8a57232..0af8b4e 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Enabled Filtered"</item>
<item msgid="2779123106632690576">"Enabled"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Headers Filtered"</item>
+ <item msgid="4818549483446395865">"A2DP Media Packets Filtered"</item>
+ <item msgid="8207123990453243311">"RFCOMM Channel Filtered"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Disabled"</item>
+ <item msgid="5884245882825346396">"Magic"</item>
+ <item msgid="6569400572915342949">"Header"</item>
+ <item msgid="1239386221416967664">"Full Filter"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 327e4e9..de63386 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Enabled Filtered"</item>
<item msgid="2779123106632690576">"Enabled"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Headers filtered"</item>
+ <item msgid="4818549483446395865">"A2DP media packets filtered"</item>
+ <item msgid="8207123990453243311">"RFCOMM channel filtered"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Disabled"</item>
+ <item msgid="5884245882825346396">"Magic"</item>
+ <item msgid="6569400572915342949">"Header"</item>
+ <item msgid="1239386221416967664">"Full filter"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 327e4e9..de63386 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Enabled Filtered"</item>
<item msgid="2779123106632690576">"Enabled"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Headers filtered"</item>
+ <item msgid="4818549483446395865">"A2DP media packets filtered"</item>
+ <item msgid="8207123990453243311">"RFCOMM channel filtered"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Disabled"</item>
+ <item msgid="5884245882825346396">"Magic"</item>
+ <item msgid="6569400572915342949">"Header"</item>
+ <item msgid="1239386221416967664">"Full filter"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-en-rXC/arrays.xml b/packages/SettingsLib/res/values-en-rXC/arrays.xml
index 8af0a4a..30c9a49 100644
--- a/packages/SettingsLib/res/values-en-rXC/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rXC/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Enabled Filtered"</item>
<item msgid="2779123106632690576">"Enabled"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Headers Filtered"</item>
+ <item msgid="4818549483446395865">"A2DP Media Packets Filtered"</item>
+ <item msgid="8207123990453243311">"RFCOMM Channel Filtered"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Disabled"</item>
+ <item msgid="5884245882825346396">"Magic"</item>
+ <item msgid="6569400572915342949">"Header"</item>
+ <item msgid="1239386221416967664">"Full Filter"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 3813808..e272cd5 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrado habilitado"</item>
<item msgid="2779123106632690576">"Habilitado"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 3e97c32..fcb454a 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"No se pueden reproducir las descargas aquí"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Vuelve a intentarlo después del anuncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositivo para reproducir aquí"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"El dispositivo no está aprobado para reproducir"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No se puede reproducir el contenido multimedia aquí"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
@@ -585,7 +581,7 @@
<string name="user_add_user_type_title" msgid="551279664052914497">"Agregar"</string>
<string name="user_new_user_name" msgid="60979820612818840">"Usuario nuevo"</string>
<string name="user_new_profile_name" msgid="2405500423304678841">"Perfil nuevo"</string>
- <string name="user_info_settings_title" msgid="6351390762733279907">"Datos de usuario"</string>
+ <string name="user_info_settings_title" msgid="6351390762733279907">"Datos del usuario"</string>
<string name="profile_info_settings_title" msgid="105699672534365099">"Datos del perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar un bloqueo de pantalla que proteja tus aplicaciones y datos personales."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 4924407..fc28d4ae 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Habilitado con filtros"</item>
<item msgid="2779123106632690576">"Habilitado"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index eb176a9..7c8421f 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir contenido en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"No se pueden reproducir descargas aquí"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Prueba de nuevo después del anuncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositivo para reproducir contenido aquí"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo no aprobado para reproducir contenido"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No se puede reproducir el contenido multimedia aquí"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index 0402ac2..282bfb1 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Luba filtreeritud"</item>
<item msgid="2779123106632690576">"Lubatud"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (vaikeseade)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 3f0a6ed..fd9bcd6 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"See telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"See tahvelarvuti"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Selles seadmes ei saa esitada"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lülitamiseks täiendage kontot"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Siin ei saa allalaaditud faile esitada"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Proovige pärast reklaami uuesti"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Äratage seade siin esitamiseks"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Seade ei ole esitamiseks heaks kiidetud"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Seda meediat ei saa siin esitada"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
<string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index d15712a..8cd3da8 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Gaituta baina iragazita"</item>
<item msgid="2779123106632690576">"Gaituta"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (lehenetsia)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 4fe2e23..82e0eea 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefono hau"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tableta hau"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ezin da erreproduzitu gailu honetan"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Aldatzeko, bertsio-berritu kontua"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Deskargak ezin dira hemen erreproduzitu"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Saiatu berriro iragarkiaren ondoren"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktibatu gailua hemen erreproduzitzeko"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Gailua ez dago erreproduzitzeko onartuta"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ezin da erreproduzitu multimedia-eduki hau hemen"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 41410cb..3a7bada 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"فیلترشده فعال شده است"</item>
<item msgid="2779123106632690576">"فعال"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP نسخه ۱.۵ (پیشفرض)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index c7f01af..0732fcf 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"این تلفن"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"این رایانه لوحی"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"نمیتوان در این دستگاه پخش کرد"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"برای تغییر، حساب را ارتقا دهید"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"نمیتوان بارگیریها را در اینجا پخش کرد"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"بعداز آگهی دوباره امتحان کنید"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"برای پخش در اینجا، دستگاه را بیدار کنید"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"دستگاه برای پخش تأیید نشده است"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"نمیتوان این رسانه را اینجا پخش کرد"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
<string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 842fb8f..541ae38 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Suodatus käytössä"</item>
<item msgid="2779123106632690576">"Päällä"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (oletus)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index a81c176..089fa42 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tämä puhelin"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tämä tabletti"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ei voi toistaa tällä laitteella"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Vaihda päivittämällä tili"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Latauksia ei voi toistaa täällä"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Kokeile uudelleen mainoksen jälkeen"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivoi laite, jotta voit toistaa sillä"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Laitetta ei ole hyväksytty toistoa varten"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Mediaa ei voi toistaa tällä"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
<string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index dfa6db3..4bcf9d2 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtres activés"</item>
<item msgid="2779123106632690576">"Activé"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (par défaut)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6e1d09e..489bea1c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de faire jouer le contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à jour le compte pour passer à la version payante"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Lecture des téléchargements impossible ici"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Réessayez après l\'annonce"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activer l\'appareil pour faire jouer le contenu ici"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"L\'appareil n\'est pas autorisé à faire jouer le contenu"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossible de faire jouer ce contenu multimédia ici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 92546da..b154354 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Activé et filtré"</item>
<item msgid="2779123106632690576">"Activé"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (par défaut)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index f74b2bb..a4d5f20 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de lire du contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à niveau le compte pour changer"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Impossible de lire les téléchargements ici"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Réessayez après l\'annonce"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activer l\'appareil pour lire du contenu ici"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Appareil non autorisé à lire du contenu"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossible de lire ce contenu multimédia ici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index fb8e5f2..07c4b29 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Está activado o filtrado"</item>
<item msgid="2779123106632690576">"Activada"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predeterminado)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d1d6afe..8aa4d62 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tableta"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Non se pode reproducir contido neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Cambia a conta a un plan superior para facer a modificación"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Non se poden reproducir as descargas neste dispositivo"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Téntao de novo despois de que remate o anuncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa o dispositivo para reproducir o contido aquí"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo non está autorizado para reproducir contido"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Non se pode reproducir este produto multimedia aquí"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index e527d81..69fe7bb 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ફિલ્ટર કરેલ ચાલુ છે"</item>
<item msgid="2779123106632690576">"ચાલુ છે"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ડિફૉલ્ટ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 00435d8..e253bbf 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"આ ફોન"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"આ ટૅબ્લેટ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"આ ડિવાઇસ પર ચલાવી શકતા નથી"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"સ્વિચ કરવા માટે એકાઉન્ટ અપગ્રેડ કરો"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ડાઉનલોડ કરેલું કન્ટેન્ટ અહીં ચલાવી શકતા નથી"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"જાહેરાત પછી ફરીથી પ્રયાસ કરો"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"અહીં ચલાવવા માટે ડિવાઇસને સક્રિય કરો"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ડિવાઇસ દ્વારા ચલાવવાની મંજૂરી આપવામાં આવી નથી"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"અહીં આ મીડિયા ચલાવી શકતા નથી"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
<string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 9b8d83e..5ed88a9 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"चालू और फ़िल्टर किया गया"</item>
<item msgid="2779123106632690576">"चालू है"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (डिफ़ॉल्ट)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index b5bee94..adf09d7 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यह फ़ोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यह टैबलेट"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"इस डिवाइस पर मीडिया नहीं चलाया जा सकता"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"प्रीमियम खाते में स्विच करने के लिए, अपना खाता अपग्रेड करें"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"डाउनलोड किए गए वीडियो यहां नहीं चलाए जा सकते"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"विज्ञापन खत्म होने के बाद फिर से कोशिश करें"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"मीडिया को यहां चलाने के लिए, डिवाइस को अनलॉक करें"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"डिवाइस को मीडिया चलाने की अनुमति नहीं दी गई है"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"इस मीडिया को यहां नहीं चलाया जा सकता"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
<string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 559383a..812f8d2 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Omogućeno filtrirano"</item>
<item msgid="2779123106632690576">"Omogućeno"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Filtrirana zaglavlja"</item>
+ <item msgid="4818549483446395865">"Filtrirani A2DP medijski paketi"</item>
+ <item msgid="8207123990453243311">"Filtrirani RFCOMM kanal"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Onemogućeno"</item>
+ <item msgid="5884245882825346396">"Čarolija"</item>
+ <item msgid="6569400572915342949">"Zaglavlje"</item>
+ <item msgid="1239386221416967664">"Potpuni filtar"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (zadano)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index bf6ee8b..9489d6e 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nije moguće reproducirati na ovom uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite račun radi prebacivanja"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Preuzimanja se ne mogu reproducirati ovdje"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Pokušajte ponovo nakon oglasa"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivirajte uređaj da biste na njemu reproducirali"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Uređaj nije odobren za reprodukciju"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ti se mediji ne mogu reproducirati ovdje"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 409d600..55a2d28 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Szűrtek engedélyezve"</item>
<item msgid="2779123106632690576">"Engedélyezve"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (alapértelmezett)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 327acde..0d4d09d 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ez a telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ez a táblagép"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nem lehet tartalmat lejátszani ezen az eszközön"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"A váltáshoz frissítse fiókját magasabb kategóriára"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Itt nem lehet lejátszani a letöltött elemeket"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Próbálja újra a hirdetés után"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"A tartalom itteni lejátszásához ébressze fel az eszközt"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Az eszköz nem játszhat le tartalmat"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"A médiatartalom nem játszható le itt"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
<string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 009875d..d2c46ac 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Միացված է զտիչներով"</item>
<item msgid="2779123106632690576">"Միացված է"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (կանխադրված)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 1e584f9..0a3161b 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Այս հեռախոսը"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Այս պլանշետը"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Հնարավոր չէ նվագարկել այս սարքում"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Փոխելու համար անցեք հաշվի պրեմիում տարբերակին"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Հնարավոր չէ նվագարկել ներբեռնումներն այստեղ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Նորից փորձեք գովազդից հետո"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Արթնացրեք սարքը՝ այստեղ նվագարկելու համար"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Նվագարկելու համար հաստատեք սարքը"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Չհաջողվեց նվագարկել մեդիա ֆայլն այստեղ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
<string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 9527417..87cede7 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Diaktifkan Difilter"</item>
<item msgid="2779123106632690576">"Diaktifkan"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index acedc1c..2ee096b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -335,7 +335,7 @@
<string name="enable_terminal_summary" msgid="2481074834856064500">"Aktifkan aplikasi terminal yang menawarkan akses kerangka lokal"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Pemeriksaan HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Setel perilaku pemeriksaan HDCP"</string>
- <string name="debug_debugging_category" msgid="535341063709248842">"Debugging"</string>
+ <string name="debug_debugging_category" msgid="535341063709248842">"Proses debug"</string>
<string name="debug_app" msgid="8903350241392391766">"Pilih aplikasi debug"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Tidak ada aplikasi debug yang disetel"</string>
<string name="debug_app_set" msgid="6599535090477753651">"Aplikasi debug: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ponsel ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat memutar di perangkat ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade akun untuk beralih"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tidak dapat memutar hasil download di sini"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Coba lagi setelah iklan"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Mengaktifkan perangkat untuk memutar di sini"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Perangkat tidak disetujui untuk memutar"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tidak dapat memutar media ini di sini"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index 0b5b978..5c5841c 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Kveikt á síuðu"</item>
<item msgid="2779123106632690576">"Kveikt"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (sjálfgefið)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index cf9d475..95dc268 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Þessi sími"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Þessi spjaldtölva"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ekki er hægt að spila í þessu tæki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppfærðu reikninginn til að skipta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Ekki er hægt að spila niðurhal hér"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Reyndu aftur eftir auglýsinguna"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vektu tæki til að spila hér"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Tæki er ekki samþykkt til spilunar"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ekki er hægt að spila þetta efni hér"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
<string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index ae1e515..4cd775a 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtro attivo"</item>
<item msgid="2779123106632690576">"Attiva"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (versione predefinita)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 524e83d..dc96364 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo telefono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Questo tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossibile riprodurre su questo dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Esegui l\'upgrade dell\'account per cambiare"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Qui non è possibile riprodurre i download"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Riprova dopo l\'annuncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Riattiva il dispositivo per riprodurre qui"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo non approvato per la riproduzione"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossibile riprodurre questo contenuto multimediale qui"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
<string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 5d72aff..a09bccb 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"המסננים המופעלים"</item>
<item msgid="2779123106632690576">"מופעל"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ברירת המחדל)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c1a2a4c..5c54d62 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"הטלפון הזה"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"הטאבלט הזה"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"לא ניתן להפעיל במכשיר הזה"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"צריך לשדרג את החשבון כדי לעבור"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"לא ניתן להפעיל את ההורדות כאן"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"אפשר לנסות שוב לאחר המודעה"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"צריך להוציא את המכשיר ממצב השינה כדי להפעיל כאן"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"המכשיר לא קיבל אישור להפעלה"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"אי אפשר להפעיל את המדיה הזו כאן"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
<string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 775e31c..2090266 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"有効(フィルタ済み)"</item>
<item msgid="2779123106632690576">"有効"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5(デフォルト)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7143f47..09984c2 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"このスマートフォン"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"このタブレット"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"このデバイスで再生できません"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"アカウントを更新して切り替えてください"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ダウンロードしたコンテンツをここでは再生できません"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"広告が表示されてから、もう一度試してください"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ここで再生するにはデバイスを起動してください"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"このデバイスでの再生が許可されていません"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"このメディアはここで再生できません"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
<string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index f3545b6..616633f 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"გაფილტრულის ჩართვა"</item>
<item msgid="2779123106632690576">"ჩართულია"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ნაგულისხმევი)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 61bad37..2abd85a 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ეს ტელეფონი"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ეს ტაბლეტი"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ეს ტელეფონი"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ამ მოწყობილობაზე დაკვრა შეუძლებელია"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"გადასართავად განაახლეთ ანგარიში"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"აქ ჩამოტვირთვების თამაში შეუძლებელია"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"სცადეთ ხელახლა რეკლამის შემდეგ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"დასაკრავად გამოაღვიძეთ ტელეფონი"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"მოწყობილობა არ არის ავტორიზებული დასაკრავად"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ამ მედიის აქ დაკვრა შეუძლებელია"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
<string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index 3fd1b50..9aa8d85 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Сүзгіленгендері қосулы"</item>
<item msgid="2779123106632690576">"Қосулы"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (әдепкі)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 111c6c2..ba68253 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Осы телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Осы планшет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Осы құрылғыда ойнату мүмкін емес."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Ауысу үшін аккаунтты жаңартыңыз."</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Жүктеп алынғандарды осы жерде ойнату мүмкін емес."</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Жарнамадан кейін қайталап көріңіз."</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Осы жерде ойнату үшін құрылғыны оятыңыз."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Ойнату үшін авторизация керек."</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Бұл мультимедиа файлын осы жерде ойнату мүмкін емес."</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
<string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index 2269df1..c2c1290 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"បានបើកការត្រង"</item>
<item msgid="2779123106632690576">"បានបើក"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (លំនាំដើម)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 36769b9..2e33159 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ថេប្លេតនេះ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"មិនអាចចាក់នៅលើឧបករណ៍នេះបានទេ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ដំឡើងកម្រិតគណនី ដើម្បីប្ដូរ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"មិនអាចចាក់ខ្លឹមសារដែលបានទាញយកនៅទីនេះបានទេ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ព្យាយាមម្ដងទៀត បន្ទាប់ពីការផ្សាយពាណិជ្ជកម្ម"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ដាស់ឧបករណ៍ឱ្យចាក់នៅទីនេះ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ឧបករណ៍មិនយល់ព្រមឱ្យចាក់ទេ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"មិនអាចចាក់មេឌៀនេះនៅទីនេះបានទេ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string>
<string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index 975f60f..22bfe22 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ಫಿಲ್ಟರ್ ಮಾಡುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</item>
<item msgid="2779123106632690576">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ಡೀಫಾಲ್ಟ್)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 42749bf..a3ce673 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ಈ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ಬದಲಾಯಿಸಲು ಖಾತೆಯನ್ನು ಅಪ್ಗ್ರೇಡ್ ಮಾಡಿ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ಇಲ್ಲಿ ಡೌನ್ಲೋಡ್ಗಳನ್ನು ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ಜಾಹೀರಾತಿನ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧನವನ್ನು ಎಚ್ಚರಿಸಿ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ಸಾಧನವನ್ನು ಪ್ಲೇ ಮಾಡಲು ಅನುಮೋದಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ಈ ಮಾಧ್ಯಮವನ್ನು ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
<string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index 16b840b..547eabf 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"필터링 사용 설정됨"</item>
<item msgid="2779123106632690576">"사용 설정됨"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5(기본값)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a65afb1..27c5a70 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"이 휴대전화"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"태블릿"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"이 기기에서 재생할 수 없음"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"전환하려면 계정을 업그레이드하세요."</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"여기서 다운로드한 콘텐츠를 재생할 수 없습니다."</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"광고 후에 다시 시도해 주세요."</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"기기 절전 모드 해제 후 여기에서 재생"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"기기에서 재생을 승인하지 않음"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"여기에서 이 미디어를 재생할 수 없음"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
<string name="help_label" msgid="3528360748637781274">"고객센터"</string>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index 700aae1..6e3cd74 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Чыпкалар иштетилди"</item>
<item msgid="2779123106632690576">"Иштетилди"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Демейки)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index f893fa4..604731a 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ушул телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ушул планшет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Бул түзмөктө ойнотуу мүмкүн эмес"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Которулуу үчүн аккаунтуңузду жаңыртыңыз"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Жүктөлүп алынгандарды бул жерде ойнотуу мүмкүн эмес"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Жарнамадан кийин кайталап көрүңүз"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Угуу үчүн түзмөктү уйку режиминен чыгарыңыз"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Бул түзмөктө ойнотуу үчүн уруксат алуу керек"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Бул медианы ойнотуу мүмкүн эмес"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
<string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index f116e6f..b74aab74 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ເປີດການກັ່ນຕອງແລ້ວ"</item>
<item msgid="2779123106632690576">"ເປີດໃຊ້ແລ້ວ"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ຄ່າເລີ່ມຕົ້ນ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 37ef733..5722f4f 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ແທັບເລັດນີ້"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ຫຼິ້ນຢູ່ອຸປະກອນນີ້ບໍ່ໄດ້"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ອັບເກຣດບັນຊີເພື່ອສະຫຼັບ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ບໍ່ສາມາດຫຼິ້ນເນື້ອຫາທີ່ດາວໂຫຼດຢູ່ນີ້ໄດ້"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ລອງໃໝ່ຫຼັງຈາກໂຄສະນາ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ປຸກອຸປະກອນເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ອຸປະກອນບໍ່ອະນຸມັດໃຫ້ຫຼິ້ນ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ຫຼິ້ນມີເດຍນີ້ຢູ່ບ່ອນນີ້ບໍ່ໄດ້"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
<string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index c0aafdc..a25078c 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Įgalinta filtruota"</item>
<item msgid="2779123106632690576">"Įgalinta"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (numatytoji)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 05c65c4..949a865 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis telefonas"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetinis kompiuteris"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Negalima leisti šiame įrenginyje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Jei norite perjungti, naujovinkite paskyrą"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Čia negalima paleisti atsisiuntimų"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Bandykite dar kartą po skelbimo"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Pažadinkite įrenginį, kad galėtumėte čia leisti"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Įrenginys nepatvirtintas, kad būtų galima leisti"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Čia negalima leisti šio medijos failo"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
<string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index 0f9ee52..908ebf8 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Iespējot filtrētos"</item>
<item msgid="2779123106632690576">"Iespējots"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (noklusējums)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index b125b40..0e23cee 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis tālrunis"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetdators"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nevar atskaņot šajā ierīcē."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lai pārslēgtu, jauniniet kontu"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Šeit nevar atskaņot lejupielādes"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Mēģiniet vēlreiz, kad beigsies reklāma"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Lai atskaņotu šeit, aktivizējiet ierīci."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Ierīce nav apstiprināta atskaņošanai."</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Šo multivides saturu nevar atskaņot šeit."</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
<string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index 41427c1..98b3de2 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Овозможено е филтрирано"</item>
<item msgid="2779123106632690576">"Овозможено"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Стандардна)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index a843ea1..f57412c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овој телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овој таблет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не може да се пушти на уредов"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надградете ја сметката за да се префрлите"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Не може да се пуштаат преземања тука"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Обидете се повторно по рекламата"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Разбудете го уредот за да пуштате овде"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Уредот не е одобрен за репродукција"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Не може да се пуштат аудиовизуелните содржини овде"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
<string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index 98e3bd6..75a5921 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ഫിൽട്ടറിംഗ് പ്രവർത്തനക്ഷമമാക്കി"</item>
<item msgid="2779123106632690576">"പ്രവർത്തനക്ഷമമാക്കി"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ഡിഫോൾട്ട്)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index da27136..6d39bc2 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ഈ ടാബ്ലെറ്റ്"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ഈ ഉപകരണത്തിൽ പ്ലേ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"അക്കൗണ്ട് മാറുന്നതിന്, അത് അപ്ഗ്രേഡ് ചെയ്യുക"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ഡൗൺലോഡ് ചെയ്തവ ഇവിടെ പ്ലേ ചെയ്യാനാകില്ല"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"പരസ്യത്തിന് ശേഷം വീണ്ടും ശ്രമിക്കുക"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ഇവിടെ പ്ലേ ചെയ്യാൻ ഉപകരണം സജീവമാക്കുക"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ഉപകരണത്തിന് പ്ലേ ചെയ്യാനുള്ള അനുമതിയില്ല"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ഈ മീഡിയ ഇവിടെ പ്ലേ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
<string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index f3c10d7..2ca88a5 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Идэвхжүүлсэн Шүүсэн"</item>
<item msgid="2779123106632690576">"Идэвхжүүлсэн"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Өгөгдмөл)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 0af5596..b1c25f5 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Энэ утас"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Энэ таблет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Энэ төхөөрөмжид тоглуулах боломжгүй"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Сэлгэхийн тулд бүртгэлийг сайжруулна уу"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Татаж авсан файлыг энд тоглуулах боломжгүй"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Зарын дараа дахин оролдоно уу"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Энд тоглуулахын тулд төхөөрөмжийг сэрээнэ үү"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Төхөөрөмжийг тоглуулахыг зөвшөөрөөгүй"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Энэ медиаг энд тоглуулах боломжгүй"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
<string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index c37baaa2..eaf4c66 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"फिल्टर केलेले सुरू केले"</item>
<item msgid="2779123106632690576">"सुरू केले"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (डीफॉल्ट)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 9773ecf..b015ba8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"हा फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"हा टॅबलेट"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"या डिव्हाइसवर प्ले करू शकत नाही"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"स्विच करण्यासाठी खाते अपग्रेड करा"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"येथे डाउनलोड प्ले केले जाऊ शकत नाही"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"जाहिरातीनंतर पुन्हा प्रयत्न करा"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"येथे प्ले करण्यासाठी डिव्हाइस सुरू करा"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"प्ले करण्यासाठी डिव्हाइस हे मंजुरी दिलेले नाही"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"हा मीडिया येथे प्ले करू शकत नाही"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
<string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index b19f038..727f475 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Didayakan Ditapis"</item>
<item msgid="2779123106632690576">"Didayakan"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Lalai)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 6e7d430..c557bfd 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefon ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat dimainkan pada peranti ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Tingkatkan akaun untuk bertukar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tidak dapat memainkan muat turun di sini"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Cuba lagi selepas iklan"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Bangkitkan peranti untuk main di sini"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Peranti tidak diluluskan untuk main"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tidak dapat memainkan media ini di sini"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index 3398c5b..768b749 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"စစ်ထုတ်ထားသည်များကို ဖွင့်ထားသည်"</item>
<item msgid="2779123106632690576">"ဖွင့်ထားသည်"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (မူလ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 197143a..dc013d5 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ဤဖုန်း"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ဤတက်ဘလက်"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ဤစက်ပစ္စည်းတွင် ဖွင့်၍မရပါ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ပြောင်းရန်အကောင့်ကို အဆင့်မြှင့်ပါ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ဤနေရာတွင် ဒေါင်းလုဒ်များကို ဖွင့်၍မရပါ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ကြော်ငြာအပြီးတွင် ထပ်စမ်းကြည့်ပါ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ဤနေရာတွင်ဖွင့်ရန် စက်ပစ္စည်းကိုနှိုးပါ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"စက်ပစ္စည်းက ဖွင့်ခွင့်မပြုပါ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ဤမီဒီယာကို ဒီမှာဖွင့်၍မရပါ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
<string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 928ebc3..6f2370d 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrering er slått på"</item>
<item msgid="2779123106632690576">"Slått på"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index d021702..2a14766 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Dette nettbrettet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan ikke spille på denne enheten"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oppgrader kontoen for å bytte"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan ikke spille av nedlastinger her"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Prøv igjen etter annonsen"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vekk enheten for å spille her"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten er ikke godkjent for avspilling"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan ikke spille dette medieinnholdet her"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
<string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index ac1f187..46edebe 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"फिल्टर सक्षम पारियो"</item>
<item msgid="2779123106632690576">"सक्षम पारिएको छ"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP १.५ (डिफल्ट)"</item>
<item msgid="1637054408779685086">"AVRCP १.३"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index c024503..ae7e8b3 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यो फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यो ट्याब्लेट"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"यो डिभाइसमा मिडिया प्ले गर्न मिल्दैन"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"आफूले प्रयोग गर्न चाहेको खाता अपग्रेड गर्नुहोस्"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"डाउनलोड गरिएका सामग्री यहाँ प्ले गर्न मिल्दैन"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"विज्ञापन सकिएपछि फेरि प्रयास गर्नुहोस्"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"यो मिडिया यहाँ प्ले गर्न डिभाइस सक्रिय गर्नुहोस्"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"यो डिभाइसलाई मिडिया प्ले गर्ने अनुमोदन दिइएको छैन"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"यो मिडिया यहाँ प्ले गर्न मिल्दैन"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि अन गर्नुहोस्"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
<string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 7c90eab..b839ffe7 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Gefilterd staat aan"</item>
<item msgid="2779123106632690576">"Aangezet"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (standaard)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 3090990..55852d2 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Deze telefoon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Deze tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan niet afspelen op dit apparaat"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade het account om te schakelen"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Kan hier geen downloads afspelen"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Probeer het na de advertentie nog een keer"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activeer het apparaat om hier af te spelen"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Apparaat niet goedgekeurd voor afspelen"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan deze media hier niet afspelen"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index a6c40b0..57da268 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ଫିଲ୍ଟର୍କୁ ସକ୍ଷମ କରାଯାଇଛି"</item>
<item msgid="2779123106632690576">"ସକ୍ଷମ କରାଯାଇଛି"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ଡିଫଲ୍ଟ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index a509f31..1e61b24 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ଏହି ଟାବଲେଟ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ଏହି ଡିଭାଇସରେ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ସ୍ୱିଚ କରିବା ପାଇଁ ଆକାଉଣ୍ଟକୁ ଅପଗ୍ରେଡ କରନ୍ତୁ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ଏଠାରେ ଡାଉନଲୋଡଗୁଡ଼ିକୁ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ବିଜ୍ଞାପନ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ଏଠାରେ ପ୍ଲେ କରିବା ପାଇଁ ଡିଭାଇସକୁ ସକ୍ରିୟ କରନ୍ତୁ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ପ୍ଲେ କରିବା ପାଇଁ ଡିଭାଇସକୁ ଅନୁମୋଦନ କରାଯାଇନାହିଁ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ଏଠାରେ ମିଡିଆ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
<string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index 0fd5c56..083f5aa 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ਫਿਲਟਰ ਕੀਤਿਆਂ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</item>
<item msgid="2779123106632690576">"ਚਾਲੂ"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index dcff45c..d4b7632 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ਇਹ ਟੈਬਲੈੱਟ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ਸਵਿੱਚ ਕਰਨ ਲਈ ਖਾਤੇ ਨੂੰ ਅੱਪਗ੍ਰੇਡ ਕਰੋ"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ਡਾਊਨਲੋਡਾਂ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ਵਿਗਿਆਪਨ ਤੋਂ ਬਾਅਦ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ਇੱਥੇ ਮੀਡੀਆ ਚਲਾਉਣ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ਡੀਵਾਈਸ ਨੂੰ ਮੀਡੀਆ ਚਲਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ਇਸ ਮੀਡੀਆ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
<string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 71ecd46..87aeb50 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrowanie włączone"</item>
<item msgid="2779123106632690576">"Włączono"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (domyślnie)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 0f51432..84aa66a 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ten telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ten tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nie można odtworzyć na tym urządzeniu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uaktualnij konto, aby przełączyć"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tutaj nie można odtworzyć pobranych plików"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Spróbuj ponownie po reklamie"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wybudź urządzenie, aby odtworzyć tutaj"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Urządzenie nie ma uprawnień do odtwarzania"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Nie można odtworzyć tego pliku multimedialnego"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index f218fab..b64383f 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtro ativado"</item>
<item msgid="2779123106632690576">"Ativado"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (padrão)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 14f2e60..168207d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Tente de novo depois do anúncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ativar dispositivo para tocar aqui"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo não foi aprovado para reprodução"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir essa mídia aqui"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index e323455..b134be6 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -50,8 +50,8 @@
</string-array>
<string-array name="hdcp_checking_titles">
<item msgid="2377230797542526134">"Nunca verificar"</item>
- <item msgid="3919638466823112484">"Verificar apenas conteúdo DRM"</item>
- <item msgid="9048424957228926377">"Verificar sempre"</item>
+ <item msgid="3919638466823112484">"Rever apenas conteúdo DRM"</item>
+ <item msgid="9048424957228926377">"Rever sempre"</item>
</string-array>
<string-array name="hdcp_checking_summaries">
<item msgid="4045840870658484038">"Nunca utilizar a verificação HDCP"</item>
@@ -63,6 +63,17 @@
<item msgid="6336372935919715515">"Filtrado ativado"</item>
<item msgid="2779123106632690576">"Ativado"</item>
</string-array>
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item msgid="5118179698172834473">"Cabeçalhos filtrados"</item>
+ <item msgid="4818549483446395865">"Pacotes de multimédia A2DP filtrados"</item>
+ <item msgid="8207123990453243311">"Canal RFCOMM filtrado"</item>
+ </string-array>
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item msgid="6348114316510677939">"Desativado"</item>
+ <item msgid="5884245882825346396">"Magia"</item>
+ <item msgid="6569400572915342949">"Cabeçalho"</item>
+ <item msgid="1239386221416967664">"Filtro completo"</item>
+ </string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predefinição)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c6cb7ae..91d1204 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -325,8 +325,8 @@
<string name="adb_keys_warning_message" msgid="2968555274488101220">"Revogar acesso à depuração USB de todos os computadores anteriormente autorizados?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Permitir definições de programação?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Estas definições destinam-se apenas a programação. Podem fazer com que o seu aparelho e as aplicações nele existentes falhem ou funcionem mal."</string>
- <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Verificar apps por USB"</string>
- <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Verificar as aplicações instaladas via ADB/ADT para detetar comportamento perigoso"</string>
+ <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Rever apps por USB"</string>
+ <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Rever as aplicações instaladas via ADB/ADT para detetar comportamento perigoso"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"São apresentados os dispositivos Bluetooth sem nomes (apenas endereços MAC)"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Desativa a funcionalidade de volume absoluto do Bluetooth caso existam problemas de volume com dispositivos remotos, como um volume insuportavelmente alto ou a ausência de controlo"</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Ativa a pilha de funcionalidades Bluetooth Gabeldorche."</string>
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telemóvel"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Atualize a conta para mudar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível reproduzir as transferências aqui"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Tente novamente depois do anúncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ative o dispositivo para reproduzir aqui"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo não aprovado para reprodução"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir este conteúdo multimédia aqui"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index f218fab..b64383f 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtro ativado"</item>
<item msgid="2779123106632690576">"Ativado"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (padrão)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 14f2e60..168207d 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Não é possível abrir os downloads aqui"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Tente de novo depois do anúncio"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ativar dispositivo para tocar aqui"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo não foi aprovado para reprodução"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir essa mídia aqui"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index faa15c2..8062339 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Este activat Filtrat"</item>
<item msgid="2779123106632690576">"Activat"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (prestabilit)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 23e6459..dba7507 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Această tabletă"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nu se poate reda pe acest dispozitiv"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Fă upgrade contului pentru a comuta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Aici nu se pot reda descărcări"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Încearcă din nou după anunț"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activează dispozitivul pentru a reda aici"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispozitivul nu este aprobat pentru redare"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Conținutul media nu poate fi redat aici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Oprește și repornește dispozitivul."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
<string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index 4b6e692..5f7597d 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Включены фильтры"</item>
<item msgid="2779123106632690576">"Включено"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (по умолчанию)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index a437153..76d163c 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Этот смартфон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Этот планшет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Невозможно воспроизвести на этом устройстве."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для переключения требуется премиум-аккаунт"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Не удается воспроизвести скачанные файлы"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Повторите попытку после просмотра объявления"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Для воспроизведения выведите устройство из спящего режима."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Для воспроизведения необходима авторизация."</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Невозможно воспроизвести медиафайл."</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
<string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index eaacfb8..b03b811 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"සබල පෙරහන් කළ"</item>
<item msgid="2779123106632690576">"සබලයි"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (පෙරනිමි)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 9887eb7..5ba553d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"මෙම ටැබ්ලටය"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"මෙම උපාංගය මත ධාවනය කළ නොහැක"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"මාරු වීමට ගිණුම උත්ශ්රේණි කරන්න"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"මෙහි බාගැනීම් වාදනය කළ නොහැක"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"දැන්වීමෙන් පසු නැවත උත්සාහ කරන්න"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"මෙහි වාදනය කිරීමට උපාංගය අවදි කරන්න"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"උපාංගය වාදනය කිරීමට අනුමත කර නැත"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"මෙම මාධ්ය මෙහි වාදනය කළ නොහැක"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
<string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index bbfe969..902531c 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Aktivované filtrované"</item>
<item msgid="2779123106632690576">"Aktivované"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (predvolené)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index e4c2b20..5e56aba6 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefón"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"V tomto zariadení sa nedá prehrávať obsah"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Inovujte účet a prejdite naň"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tu sa nedajú prehrať stiahnuté súbory"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Skúste to znova po reklame"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ak chcete prehrávať obsah tu, prebuďte zariadenie"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Prehrávanie v tomto zariadení nie je schválené"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tu sa toto médium nedá prehrať"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
<string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index b2003e5..ef5bf53 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Omogočeno filtrirano"</item>
<item msgid="2779123106632690576">"Omogočeno"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (privzeto)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 02991c4..dc65447 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ta telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ta tablični računalnik"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ni mogoče predvajati v tej napravi."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Za preklop je potrebna nadgradnja računa"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Tukaj ni mogoče predvajati prenosov"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Poskusite znova po oglasu"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Zbudite napravo, če želite predvajati tukaj."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Naprava ni odobrena za predvajanje."</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Te predstavnosti ni mogoče predvajati tukaj."</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index ed86380..c31d4fb 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Të aktivizuara të filtruara"</item>
<item msgid="2779123106632690576">"Aktiv"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (I parazgjedhur)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 9ff415d..e61c34a 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ky telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ky tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nuk mund të luhet në këtë pajisje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Përmirëso llogarinë për të ndryshuar"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Shkarkimet nuk mund të luhen këtu"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Provo përsëri pas reklamës"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Riaktivizoje pajisjen për të luajtur këtu"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Pajisja nuk është miratuar për të luajtur"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kjo media nuk mund të luhet këtu"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
<string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index a95e47b..e5a9f50 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Омогућено филтрирано"</item>
<item msgid="2779123106632690576">"Омогућено"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (подразумевано)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 4d2352d..cfac256 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овај телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овај таблет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можете да пустите на овом уређају"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надоградите налог ради пребацивања"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Преузимања не могу да се пуштају овде"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Пробајте поново после огласа"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Пробудите уређај да бисте пустили овде"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Уређај није одобрен за репродукцију"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Не можете да пустите овај медијски фајл овде"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
<string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index c63465c..4f4ded1 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrering har aktiverats"</item>
<item msgid="2779123106632690576">"Aktiverad"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (standard)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index d8dc9f6..99b8c4f 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Den här telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Den här surfplattan"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Det går inte att spela upp denna enhet"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppgradera kontot för att byta"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Det går inte att spela upp nedladdningar här"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Försök igen efter annonsen"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Väck enheten för att spela upp här"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten har inte godkänts för uppspelning"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Det går inte att spela upp detta här"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 6ed4d5a..aee1cde 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Vichujio Vilivyowekwa"</item>
<item msgid="2779123106632690576">"Imewashwa"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Chaguomsingi)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 414c218..ce3068f 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Simu hii"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Kompyuta kibao hii"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Huwezi kucheza maudhui kwenye kifaa hiki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Pata toleo jipya la akaunti ili ubadilishe"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Imeshindwa kucheza maudhui yaliyopakuliwa hapa"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Jaribu tena baada ya tangazo"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Washa skrini ya kifaa ili ucheze maudhui hapa"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Kifaa hakijaidhinishwa ili kucheza maudhui"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Huwezi kucheza maudhui haya hapa"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
<string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index 236f899..9fd1b6e 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"இயக்கப்பட்டு வடிகட்டப்பட்டது"</item>
<item msgid="2779123106632690576">"இயக்கப்பட்டது"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (இயல்பு)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 3b11cab..ea12899 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"இந்த மொபைல்"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"இந்த டேப்லெட்"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"இந்தச் சாதனத்தில் பிளே செய்ய முடியவில்லை"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"மாற்ற, கணக்கை மேம்படுத்துங்கள்"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"பதிவிறக்கங்களை இங்கே பிளே செய்ய முடியாது"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"விளம்பரம் முடிந்த பிறகு மீண்டும் முயலுங்கள்"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"இங்கே பிளே செய்ய உங்கள் சாதனத்தைச் சார்ஜ் செய்யுங்கள்"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"பிளே செய்வதற்குச் சாதனம் அனுமதிக்கப்படவில்லை"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"இந்த மீடியாவை இங்கே பிளே செய்ய முடியவில்லை"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
<string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index fb4cff1..c4494f9 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"ప్రారంభించబడింది ఫిల్టర్ చేయబడింది"</item>
<item msgid="2779123106632690576">"ప్రారంభించబడింది"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.4 (ఆటోమేటిక్ సెట్టింగ్)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index d539a3d..ed91fea 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ఈ ఫోన్"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ఈ టాబ్లెట్"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"ఈ పరికరంలో ప్లే చేయడం సాధ్యపడదు"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"మారడానికి ఖాతాను అప్గ్రేడ్ చేయండి"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ఇక్కడ డౌన్లోడ్లను ప్లే చేయడం సాధ్యపడదు"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"యాడ్ తర్వాత మళ్లీ ట్రై చేయండి"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ఇక్కడ ప్లే చేయడానికి పరికరాన్ని మేల్కొలపండి"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"ప్లే చేయడానికి పరికరానికి అధికారం ఇవ్వలేదు"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ఇక్కడ ఈ మీడియాను ప్లే చేయడం సాధ్యపడదు"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
<string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 782e95e..1fb18a0 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"เปิดใช้รายการที่กรอง"</item>
<item msgid="2779123106632690576">"เปิดใช้"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ค่าเริ่มต้น)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index beabce4..a1dec58 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"แท็บเล็ตเครื่องนี้"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"เล่นในอุปกรณ์นี้ไม่ได้"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"อัปเกรดบัญชีเพื่อเปลี่ยน"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"เล่นเนื้อหาที่ดาวน์โหลดที่นี่ไม่ได้"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"ลองอีกครั้งหลังจากโฆษณา"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ปลุกระบบอุปกรณ์เพื่อเล่นที่นี่"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"อุปกรณ์ไม่อนุมัติให้เล่น"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"เล่นสื่อนี้ที่นี่ไม่ได้"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
<string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index 19d3423..7b55436 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Na-enable Na-filter"</item>
<item msgid="2779123106632690576">"Naka-enable"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Default)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 53b6d8e..7847da6 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ang teleponong ito"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ang tablet na ito"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Hindi ma-play sa device na ito"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"I-upgrade ang account para lumipat"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Hindi mape-play ang mga download dito"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Subukan ulit pagkatapos ng ad"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"I-wake ang device para i-play dito"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Hindi naaprubahan ang device para sa pag-play"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Hindi ma-play ang media na ito rito"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 37891ae..016b5a9 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Etkin Filtrelenmiş"</item>
<item msgid="2779123106632690576">"Etkin"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Varsayılan)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 7110381..86d53e7 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu tablet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oynatılamıyor"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Geçiş yapmak için hesabı yükseltin"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"İndirilenler burada oynatılamıyor"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Reklamdan sonra tekrar deneyin"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Burada oynatmak için cihazı uyandırın"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Cihaz, oynatma işlemini onaylamadı"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Bu medya burada oynatılamıyor"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index c32da85..ff19fa3 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Увімкнено з фільтром"</item>
<item msgid="2779123106632690576">"Увімкнено"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (за умовчанням)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 54ef3a4a..92c0e11 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Цей телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Цей планшет"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можна відтворювати медіаконтент на цьому пристрої"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Щоб змінити, перейдіть на платний обліковий запис"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Тут не можна відтворювати завантажений контент"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Повторіть спробу після реклами"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Виведіть пристрій із режиму сну, щоб відтворювати медіаконтент"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Пристрій не схвалений для відтворення медіаконтенту"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"На пристрої не можна відтворювати цей медіафайл"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
<string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index db9941e..09cd765 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"فعال کردہ فلٹر کردہ"</item>
<item msgid="2779123106632690576">"فعال"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (ڈیفالٹ)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b1bd695..94bb557 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"یہ فون"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"یہ ٹیبلیٹ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"اس آلے پر چلایا نہیں جا سکتا"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"سوئچ کرنے کے لیے اکاؤنٹ اپ گریڈ کریں"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"ڈاؤن لوڈز کو یہاں چلایا نہیں جا سکتا"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"اشتہار کے بعد پھر سے کوشش کریں"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"یہاں چلانے کے لیے آلہ کو اٹھائیں"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"آلہ کو چلانے کے لیے اجازت نہیں دی گئی ہے"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"یہاں اس میڈیا کو چلایا نہیں جا سکتا"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
<string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index edbd180..0893e06 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Filtrlar yoniq"</item>
<item msgid="2779123106632690576">"Yoniq"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (asosiy)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 2df56d7..48705dd 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Shu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Shu planshet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu qurilmada ijro etilmaydi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oʻtish uchun hisobingizni yangilang"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Yuklab olingan fayllar ijro etilmaydi"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Reklamadan keyin qayta urining"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ijro etish uchun qurilmani uyqu rejimidan chiqaring."</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Qurilmaga ijro etish uchun ruxsat berilmagan"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Media fayl ijro etilmaydi"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
<string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index ee599d6..fd9ac04 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Đã bật và lọc"</item>
<item msgid="2779123106632690576">"Đã bật"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (Mặc định)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index e4f392f..1b7d651 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Điện thoại này"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Máy tính bảng này"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Không phát được trên thiết bị này"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nâng cấp tài khoản để chuyển đổi"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Không thể phát các tệp đã tải xuống tại đây"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Thử lại sau quảng cáo"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Đánh thức thiết bị để phát tại đây"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Thiết bị chưa được phép phát"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Không thể phát nội dung nghe nhìn này tại đây"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
<string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 2a85d31..1b856c7 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"已启用“已过滤”"</item>
<item msgid="2779123106632690576">"已启用"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5(默认)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 1cf0acf..1716124 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"这部手机"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"这台平板电脑"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"无法在此设备上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"升级帐号后才能切换"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"无法在此设备上播放下载的内容"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"广告之后重试"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"若要在此设备上播放,请唤醒设备"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"设备未获准播放"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"无法在此设备上播放该媒体内容"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
<string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index a84f0e2..6170f4a 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"已啟用篩選"</item>
<item msgid="2779123106632690576">"已啟用"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (預設)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index d195cf8..56f17fa 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"此手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"此平板電腦"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這部手機"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在此裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"無法在此播放下載內容"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"請在廣告結束後再試一次"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"喚醒裝置即可在此播放"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"裝置未獲核准播放"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"無法在此播放此媒體內容"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index b69fd53..9241798 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"已啟用篩選結果"</item>
<item msgid="2779123106632690576">"已啟用"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"AVRCP 1.5 (預設)"</item>
<item msgid="1637054408779685086">"AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 9511db8..8bfbd7a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"這支手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"這台平板電腦"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在這部裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"這裡無法播放下載內容"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"請在廣告結束後再試一次"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"必須喚醒裝置才能在此播放"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"裝置未獲准播放"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"無法在此播放這個媒體內容"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 0494f1c..f36d99c 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -63,6 +63,13 @@
<item msgid="6336372935919715515">"Okuhlungiwe okunikwe amandla"</item>
<item msgid="2779123106632690576">"Kunikwe amandla"</item>
</string-array>
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:0 (5118179698172834473) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:1 (4818549483446395865) -->
+ <!-- no translation found for bt_hci_snoop_log_filters_entries:2 (8207123990453243311) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:0 (6348114316510677939) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:1 (5884245882825346396) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:2 (6569400572915342949) -->
+ <!-- no translation found for bt_hci_snoop_log_profile_filter_entries:3 (1239386221416967664) -->
<string-array name="bluetooth_avrcp_versions">
<item msgid="6603880723315236832">"I-AVRCP 1.5 (Okuzenzakalelayo)"</item>
<item msgid="1637054408779685086">"I-AVRCP 1.3"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index e921efc..6c35510 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -540,17 +540,13 @@
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Le foni"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Le thebulethi"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
- <!-- no translation found for media_output_status_unknown_error (5098565887497902222) -->
- <skip />
+ <string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ayikwazi ukudlala kule divayisi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Thuthukisa i-akhawunti ukuze ushintshe"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"Awukwazi ukudlala okudawunilodiwe lapha"</string>
<string name="media_output_status_try_after_ad" msgid="8312579066856015441">"Zama futhi ngemva kwesikhangiso"</string>
- <!-- no translation found for media_output_status_device_in_low_power_mode (8184631698321758451) -->
- <skip />
- <!-- no translation found for media_output_status_unauthorized (5880222828273853838) -->
- <skip />
- <!-- no translation found for media_output_status_track_unsupported (5576313219317709664) -->
- <skip />
+ <string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vusa idivayisi ukuze udlale lapha"</string>
+ <string name="media_output_status_unauthorized" msgid="5880222828273853838">"Idivayisi ayigunyaziwe ukuthi idlale"</string>
+ <string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Awukwazi ukudlala le midiya lapha"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
<string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 7cd8d70..09a1ba2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -99,6 +99,7 @@
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
Settings.Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED,
+ Settings.Global.Wearable.UPGRADE_DATA_MIGRATION_STATUS,
Settings.Global.HDR_CONVERSION_MODE,
Settings.Global.HDR_FORCE_CONVERSION_TYPE,
};
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index dcddde4..210a387 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -131,6 +131,7 @@
Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
+ Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index d733dfb..be49940 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -404,5 +404,12 @@
}));
VALIDATORS.put(Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.SCREENSHOT_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.UPGRADE_DATA_MIGRATION_STATUS,
+ new DiscreteValueValidator(
+ new String[] {
+ String.valueOf(Global.Wearable.UPGRADE_DATA_MIGRATION_NOT_NEEDED),
+ String.valueOf(Global.Wearable.UPGRADE_DATA_MIGRATION_PENDING),
+ String.valueOf(Global.Wearable.UPGRADE_DATA_MIGRATION_DONE)
+ }));
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 1c5e6ea..39cd24a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -191,6 +191,8 @@
ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 5039624..4777680 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -265,6 +265,7 @@
<uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
<uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
<uses-permission android:name="android.permission.MANAGE_LOW_POWER_STANDBY" />
+ <uses-permission android:name="android.permission.SET_LOW_POWER_STANDBY_PORTS" />
<uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
<uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
<uses-permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION" />
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 ed6e619..ab36d58 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
@@ -51,9 +51,12 @@
defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
) {
- // Usually this would be a typealias, but a SAM provides better java interop
- fun interface ClockChangeListener {
- fun onClockChanged()
+ interface ClockChangeListener {
+ // Called when the active clock changes
+ fun onCurrentClockChanged() {}
+
+ // Called when the list of available clocks changes
+ fun onAvailableClocksChanged() {}
}
private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
@@ -92,7 +95,7 @@
protected set(value) {
if (field != value) {
field = value
- scope.launch(mainDispatcher) { onClockChanged() }
+ scope.launch(mainDispatcher) { onClockChanged { it.onCurrentClockChanged() } }
}
}
@@ -164,9 +167,9 @@
Assert.isNotMainThread()
}
- private fun onClockChanged() {
+ private fun onClockChanged(func: (ClockChangeListener) -> Unit) {
assertMainThread()
- clockChangeListeners.forEach { it.onClockChanged() }
+ clockChangeListeners.forEach(func)
}
private fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
@@ -241,6 +244,7 @@
}
private fun connectClocks(provider: ClockProvider) {
+ var isAvailableChanged = false
val currentId = currentClockId
for (clock in provider.getClocks()) {
val id = clock.clockId
@@ -251,10 +255,11 @@
"Clock Id conflict: $id is registered by both " +
"${provider::class.simpleName} and ${current.provider::class.simpleName}"
)
- return
+ continue
}
availableClocks[id] = ClockInfo(clock, provider)
+ isAvailableChanged = true
if (DEBUG) {
Log.i(TAG, "Added ${clock.clockId}")
}
@@ -263,24 +268,35 @@
if (DEBUG) {
Log.i(TAG, "Current clock ($currentId) was connected")
}
- onClockChanged()
+ onClockChanged { it.onCurrentClockChanged() }
}
}
+
+ if (isAvailableChanged) {
+ onClockChanged { it.onAvailableClocksChanged() }
+ }
}
private fun disconnectClocks(provider: ClockProvider) {
+ var isAvailableChanged = false
val currentId = currentClockId
for (clock in provider.getClocks()) {
availableClocks.remove(clock.clockId)
+ isAvailableChanged = true
+
if (DEBUG) {
Log.i(TAG, "Removed ${clock.clockId}")
}
if (currentId == clock.clockId) {
Log.w(TAG, "Current clock ($currentId) was disconnected")
- onClockChanged()
+ onClockChanged { it.onCurrentClockChanged() }
}
}
+
+ if (isAvailableChanged) {
+ onClockChanged { it.onAvailableClocksChanged() }
+ }
}
fun getClocks(): List<ClockMetadata> {
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 176bb6b..ec860b5 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -451,7 +451,6 @@
-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
@@ -736,7 +735,6 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
index 91f3309..26eefa9 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
@@ -252,49 +252,49 @@
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor primaryFixedDarker =
+ public static final DynamicColor primaryFixedDim =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onPrimaryFixed =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 10.0,
- (s) -> primaryFixedDarker);
+ (s) -> primaryFixedDim);
public static final DynamicColor onPrimaryFixedVariant =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 30.0,
- (s) -> primaryFixedDarker);
+ (s) -> primaryFixedDim);
public static final DynamicColor secondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor secondaryFixedDarker =
+ public static final DynamicColor secondaryFixedDim =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onSecondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 10.0,
- (s) -> secondaryFixedDarker);
+ (s) -> secondaryFixedDim);
public static final DynamicColor onSecondaryFixedVariant =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 30.0,
- (s) -> secondaryFixedDarker);
+ (s) -> secondaryFixedDim);
public static final DynamicColor tertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor tertiaryFixedDarker =
+ public static final DynamicColor tertiaryFixedDim =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onTertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 10.0,
- (s) -> tertiaryFixedDarker);
+ (s) -> tertiaryFixedDim);
public static final DynamicColor onTertiaryFixedVariant =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 30.0,
- (s) -> tertiaryFixedDarker);
+ (s) -> tertiaryFixedDim);
/**
* These colors were present in Android framework before Android U, and used by MDC controls.
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
deleted file mode 100644
index 8497ff0..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
- and the security view. -->
-<com.android.keyguard.KeyguardHostView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_host_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:paddingTop="@dimen/keyguard_lock_padding"
- android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
- from this view when bouncer is shown -->
-
- <com.android.keyguard.KeyguardSecurityContainer
- android:id="@+id/keyguard_security_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:padding="0dp"
- android:fitsSystemWindows="true"
- android:layout_gravity="center">
- <com.android.keyguard.KeyguardSecurityViewFlipper
- android:id="@+id/view_flipper"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:paddingTop="@dimen/keyguard_security_view_top_margin"
- android:layout_gravity="center"
- android:gravity="center">
- </com.android.keyguard.KeyguardSecurityViewFlipper>
- </com.android.keyguard.KeyguardSecurityContainer>
-
-</com.android.keyguard.KeyguardHostView>
-
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml
new file mode 100644
index 0000000..426cfaf
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+
+<com.android.keyguard.KeyguardSecurityContainer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/keyguard_security_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/keyguard_lock_padding"
+ android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
+ from this view when bouncer is shown -->
+ <com.android.keyguard.KeyguardSecurityViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/keyguard_security_view_top_margin"
+ android:layout_gravity="center"
+ android:gravity="center">
+ </com.android.keyguard.KeyguardSecurityViewFlipper>
+</com.android.keyguard.KeyguardSecurityContainer>
+
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 12e5f19..738cfd7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -120,6 +120,9 @@
<!-- Minimum display time for a heads up notification, in milliseconds. -->
<integer name="heads_up_notification_minimum_time">2000</integer>
+ <!-- Display time for a sticky heads up notification, in milliseconds. -->
+ <integer name="sticky_heads_up_notification_time">60000</integer>
+
<!-- Whether to hide the notification header when the HUN is expanded. -->
<bool name="heads_up_notification_hides_header">false</bool>
@@ -460,7 +463,7 @@
<integer name="watch_heap_limit">256000</integer>
<!-- SystemUI Plugins that can be loaded on user builds. -->
- <string-array name="config_pluginWhitelist" translatable="false">
+ <string-array name="config_pluginAllowlist" translatable="false">
<item>com.android.systemui</item>
</string-array>
@@ -834,7 +837,7 @@
<string name="config_wallpaperPickerPackage" translatable="false">
com.android.wallpaper
</string>
-
+
<!-- Whether the floating rotation button should be on the left/right in the device's natural
orientation -->
<bool name="floating_rotation_button_position_left">true</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index ead1a10..c4f1ce8 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -29,8 +29,9 @@
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
-import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser
import com.android.systemui.Dumpable
@@ -60,9 +61,27 @@
* Indicates the origin for an active unlock request.
*/
enum class ActiveUnlockRequestOrigin {
+ /**
+ * Trigger ActiveUnlock on wake ups that'd trigger FaceAuth, see [FaceWakeUpTriggersConfig]
+ */
WAKE,
+
+ /**
+ * Trigger ActiveUnlock on unlock intents. This includes the bouncer showing or tapping on
+ * a notification. May also include wakeups: [wakeupsConsideredUnlockIntents].
+ */
UNLOCK_INTENT,
+
+ /**
+ * Trigger ActiveUnlock on biometric failures. This may include soft errors depending on
+ * the other settings. See: [faceErrorsToTriggerBiometricFailOn],
+ * [faceAcquireInfoToTriggerBiometricFailOn].
+ */
BIOMETRIC_FAIL,
+
+ /**
+ * Trigger ActiveUnlock when the assistant is triggered.
+ */
ASSISTANT,
}
@@ -85,6 +104,7 @@
private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>()
private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>()
private var wakeupsConsideredUnlockIntents = mutableSetOf<Int>()
+ private var wakeupsToForceDismissKeyguard = mutableSetOf<Int>()
private val settingsObserver = object : ContentObserver(handler) {
private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
@@ -97,6 +117,8 @@
secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)
private val wakeupsConsideredUnlockIntentsUri =
secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)
+ private val wakeupsToForceDismissKeyguardUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD)
fun register() {
registerUri(
@@ -108,6 +130,7 @@
faceAcquireInfoUri,
unlockIntentWhenBiometricEnrolledUri,
wakeupsConsideredUnlockIntentsUri,
+ wakeupsToForceDismissKeyguardUri,
)
)
@@ -182,6 +205,15 @@
wakeupsConsideredUnlockIntents,
setOf(WAKE_REASON_UNFOLD_DEVICE))
}
+
+ if (selfChange || uris.contains(wakeupsToForceDismissKeyguardUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ getCurrentUser()),
+ wakeupsToForceDismissKeyguard,
+ setOf(WAKE_REASON_UNFOLD_DEVICE))
+ }
}
/**
@@ -249,6 +281,14 @@
}
/**
+ * Whether the PowerManager wake reason should force dismiss the keyguard if active
+ * unlock is successful.
+ */
+ fun shouldWakeupForceDismissKeyguard(pmWakeReason: Int): Boolean {
+ return wakeupsToForceDismissKeyguard.contains(pmWakeReason)
+ }
+
+ /**
* Whether to trigger active unlock based on where the request is coming from and
* the current settings.
*/
@@ -321,6 +361,9 @@
pw.println(" activeUnlockWakeupsConsideredUnlockIntents=${
wakeupsConsideredUnlockIntents.map { PowerManager.wakeReasonToString(it) }
}")
+ pw.println(" activeUnlockFromWakeupsToAlwaysDismissKeyguard=${
+ wakeupsToForceDismissKeyguard.map { PowerManager.wakeReasonToString(it) }
+ }")
pw.println("Current state:")
keyguardUpdateMonitor?.let {
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt b/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
index a0c43fb..788a66d 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
@@ -29,7 +29,7 @@
import java.util.stream.Collectors
import javax.inject.Inject
-/** Determines which device wake-ups should trigger face authentication. */
+/** Determines which device wake-ups should trigger passive authentication. */
@SysUISingleton
class FaceWakeUpTriggersConfig
@Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f1b90e3..5ec59ab 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -151,8 +151,13 @@
mLogBuffer = logBuffer;
mView.setLogBuffer(mLogBuffer);
- mClockChangedListener = () -> {
- setClock(mClockRegistry.createCurrentClock());
+ mClockChangedListener = new ClockRegistry.ClockChangeListener() {
+ @Override
+ public void onCurrentClockChanged() {
+ setClock(mClockRegistry.createCurrentClock());
+ }
+ @Override
+ public void onAvailableClocksChanged() { }
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
index 998dc09..57130ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
@@ -27,6 +27,7 @@
override var userId: Int = 0,
override var listening: Boolean = false,
// keepSorted
+ var alternateBouncerShowing: Boolean = false,
var biometricEnabledForUser: Boolean = false,
var bouncerIsOrWillShow: Boolean = false,
var canSkipBouncer: Boolean = false,
@@ -57,6 +58,7 @@
userId.toString(),
listening.toString(),
// keep sorted
+ alternateBouncerShowing.toString(),
biometricEnabledForUser.toString(),
bouncerIsOrWillShow.toString(),
canSkipBouncer.toString(),
@@ -96,6 +98,7 @@
userId = model.userId
listening = model.listening
// keep sorted
+ alternateBouncerShowing = model.alternateBouncerShowing
biometricEnabledForUser = model.biometricEnabledForUser
bouncerIsOrWillShow = model.bouncerIsOrWillShow
canSkipBouncer = model.canSkipBouncer
@@ -141,6 +144,7 @@
"userId",
"listening",
// keep sorted
+ "alternateBouncerShowing",
"biometricAllowedForUser",
"bouncerIsOrWillShow",
"canSkipBouncer",
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
deleted file mode 100644
index 2a389b6..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-/**
- * Base class for keyguard view. {@link #reset} is where you should
- * reset the state of your view. Use the {@link KeyguardViewCallback} via
- * {@link #getCallback()} to send information back (such as poking the wake lock,
- * or finishing the keyguard).
- *
- * Handles intercepting of media keys that still work when the keyguard is
- * showing.
- */
-public class KeyguardHostView extends FrameLayout {
-
- protected ViewMediatorCallback mViewMediatorCallback;
- private boolean mIsInteractable;
-
- public KeyguardHostView(Context context) {
- this(context, null);
- }
-
- public KeyguardHostView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDoneDrawing();
- }
- }
-
- public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
- mViewMediatorCallback = viewMediatorCallback;
- }
-
- /** Set true if the view can be interacted with */
- public void setInteractable(boolean isInteractable) {
- mIsInteractable = isInteractable;
- }
-
- /**
- * Make sure to disallow touches while transitioning the bouncer, otherwise
- * it can remain interactable even when barely visible.
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return !mIsInteractable;
- }
-
- /** True to consume any events that are sent to it */
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return true;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
deleted file mode 100644
index 77f6318..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ /dev/null
@@ -1,538 +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.keyguard;
-
-import android.app.ActivityManager;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.media.AudioManager;
-import android.os.SystemClock;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnKeyListener;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.window.OnBackAnimationCallback;
-
-import androidx.annotation.NonNull;
-
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.settingslib.Utils;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.util.ViewController;
-
-import java.io.File;
-
-import javax.inject.Inject;
-
-/** Controller for a {@link KeyguardHostView}. */
-@KeyguardBouncerScope
-public class KeyguardHostViewController extends ViewController<KeyguardHostView> {
- private static final String TAG = "KeyguardViewBase";
- public static final boolean DEBUG = KeyguardConstants.DEBUG;
- // Whether the volume keys should be handled by keyguard. If true, then
- // they will be handled here for specific media types such as music, otherwise
- // the audio service will bring up the volume dialog.
- private static final boolean KEYGUARD_MANAGES_VOLUME = false;
-
- private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardSecurityContainerController mKeyguardSecurityContainerController;
- private final TelephonyManager mTelephonyManager;
- private final ViewMediatorCallback mViewMediatorCallback;
- private final AudioManager mAudioManager;
-
- private ActivityStarter.OnDismissAction mDismissAction;
- private Runnable mCancelAction;
- private int mTranslationY;
-
- private final KeyguardUpdateMonitorCallback mUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onTrustGrantedForCurrentUser(
- boolean dismissKeyguard,
- boolean newlyUnlocked,
- TrustGrantFlags flags,
- String message
- ) {
- if (dismissKeyguard) {
- if (!mView.isVisibleToUser()) {
- // The trust agent dismissed the keyguard without the user proving
- // that they are present (by swiping up to show the bouncer). That's
- // fine if the user proved presence via some other way to the trust
- // agent.
- Log.i(TAG, "TrustAgent dismissed Keyguard.");
- }
- mSecurityCallback.dismiss(
- false /* authenticated */,
- KeyguardUpdateMonitor.getCurrentUser(),
- /* bypassSecondaryLockScreen */ false,
- SecurityMode.Invalid
- );
- } else {
- if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
- mViewMediatorCallback.playTrustedSound();
- }
- }
- }
- };
-
- private final SecurityCallback mSecurityCallback = new SecurityCallback() {
-
- @Override
- public boolean dismiss(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
- return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- authenticated, targetUserId, bypassSecondaryLockScreen, expectedSecurityMode);
- }
-
- @Override
- public void userActivity() {
- mViewMediatorCallback.userActivity();
- }
-
- @Override
- public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
- mViewMediatorCallback.setNeedsInput(needsInput);
- }
-
- /**
- * Authentication has happened and it's time to dismiss keyguard. This function
- * should clean up and inform KeyguardViewMediator.
- *
- * @param strongAuth whether the user has authenticated with strong authentication like
- * pattern, password or PIN but not by trust agents or fingerprint
- * @param targetUserId a user that needs to be the foreground user at the dismissal
- * completion.
- */
- @Override
- public void finish(boolean strongAuth, int targetUserId) {
- // If there's a pending runnable because the user interacted with a widget
- // and we're leaving keyguard, then run it.
- boolean deferKeyguardDone = false;
- if (mDismissAction != null) {
- deferKeyguardDone = mDismissAction.onDismiss();
- mDismissAction = null;
- mCancelAction = null;
- }
- if (mViewMediatorCallback != null) {
- if (deferKeyguardDone) {
- mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
- } else {
- mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
- }
- }
- }
-
- @Override
- public void reset() {
- mViewMediatorCallback.resetKeyguard();
- }
-
- @Override
- public void onCancelClicked() {
- mViewMediatorCallback.onCancelClicked();
- }
- };
-
- private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
-
- @Inject
- public KeyguardHostViewController(KeyguardHostView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- AudioManager audioManager,
- TelephonyManager telephonyManager,
- ViewMediatorCallback viewMediatorCallback,
- KeyguardSecurityContainerController.Factory
- keyguardSecurityContainerControllerFactory) {
- super(view);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mAudioManager = audioManager;
- mTelephonyManager = telephonyManager;
- mViewMediatorCallback = viewMediatorCallback;
- mKeyguardSecurityContainerController = keyguardSecurityContainerControllerFactory.create(
- mSecurityCallback);
- }
-
- /** Initialize the Controller. */
- public void onInit() {
- mKeyguardSecurityContainerController.init();
- updateResources();
- }
-
- @Override
- protected void onViewAttached() {
- mView.setViewMediatorCallback(mViewMediatorCallback);
- // Update ViewMediator with the current input method requirements
- mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
- mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
- mView.setOnKeyListener(mOnKeyListener);
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
- }
-
- @Override
- protected void onViewDetached() {
- mKeyguardUpdateMonitor.removeCallback(mUpdateCallback);
- mView.setOnKeyListener(null);
- }
-
- /** Called before this view is being removed. */
- public void cleanUp() {
- mKeyguardSecurityContainerController.onPause();
- }
-
- public void resetSecurityContainer() {
- mKeyguardSecurityContainerController.reset();
- }
-
- /**
- * Reinflate the view flipper child view.
- */
- public void reinflateViewFlipper() {
- mKeyguardSecurityContainerController.reinflateViewFlipper();
- }
-
- /**
- * Dismisses the keyguard by going to the next screen or making it gone.
- * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
- * @return True if the keyguard is done.
- */
- public boolean dismiss(int targetUserId) {
- return mSecurityCallback.dismiss(false, targetUserId, false,
- getCurrentSecurityMode());
- }
-
- /**
- * Called when the Keyguard is actively shown on the screen.
- */
- public void onResume() {
- if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
- mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON);
- mView.requestFocus();
- }
-
- public CharSequence getAccessibilityTitleForCurrentMode() {
- return mKeyguardSecurityContainerController.getTitle();
- }
-
- /**
- * Starts the animation when the Keyguard gets shown.
- */
- public void appear() {
- // We might still be collapsed and the view didn't have time to layout yet or still
- // be small, let's wait on the predraw to do the animation in that case.
- mView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- mView.getViewTreeObserver().removeOnPreDrawListener(this);
- mKeyguardSecurityContainerController.startAppearAnimation();
- return true;
- }
- });
- mView.requestLayout();
- }
-
- /**
- * Show a string explaining why the security view needs to be solved.
- *
- * @param reason a flag indicating which string should be shown, see
- * {@link KeyguardSecurityView#PROMPT_REASON_NONE},
- * {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
- * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
- * {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
- */
- public void showPromptReason(int reason) {
- mKeyguardSecurityContainerController.showPromptReason(reason);
- }
-
- public void showMessage(CharSequence message, ColorStateList colorState) {
- mKeyguardSecurityContainerController.showMessage(message, colorState);
- }
-
- public void showErrorMessage(CharSequence customMessage) {
- showMessage(customMessage, Utils.getColorError(mView.getContext()));
- }
-
- /**
- * Sets an action to run when keyguard finishes.
- *
- * @param action
- */
- public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
- if (mCancelAction != null) {
- mCancelAction.run();
- mCancelAction = null;
- }
- mDismissAction = action;
- mCancelAction = cancelAction;
- }
-
- public void cancelDismissAction() {
- setOnDismissAction(null, null);
- }
-
- public void startDisappearAnimation(Runnable finishRunnable) {
- if (!mKeyguardSecurityContainerController.startDisappearAnimation(finishRunnable)
- && finishRunnable != null) {
- finishRunnable.run();
- }
- }
-
- /**
- * Called when the Keyguard is not actively shown anymore on the screen.
- */
- public void onPause() {
- if (DEBUG) {
- Log.d(TAG, String.format("screen off, instance %s at %s",
- Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
- }
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(true);
- mKeyguardSecurityContainerController.onPause();
- mView.clearFocus();
- }
-
- /**
- * Called when the view needs to be shown.
- */
- public void showPrimarySecurityScreen() {
- if (DEBUG) Log.d(TAG, "show()");
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
- }
-
- /**
- * Fades and translates in/out the security screen.
- * Fades in as expansion approaches 0.
- * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
- * @param fraction amount of the screen that should show.
- */
- public void setExpansion(float fraction) {
- float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
- mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
- mView.setTranslationY(scaledFraction * mTranslationY);
- }
-
- /**
- * When bouncer was visible and is starting to become hidden.
- */
- public void onStartingToHide() {
- mKeyguardSecurityContainerController.onStartingToHide();
- }
-
- /** Called when bouncer visibility changes. */
- public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
- mKeyguardSecurityContainerController.onBouncerVisibilityChanged(visibility);
- }
-
- public boolean hasDismissActions() {
- return mDismissAction != null || mCancelAction != null;
- }
-
- public SecurityMode getCurrentSecurityMode() {
- return mKeyguardSecurityContainerController.getCurrentSecurityMode();
- }
-
- public int getTop() {
- int top = mView.getTop();
- // The password view has an extra top padding that should be ignored.
- if (getCurrentSecurityMode() == SecurityMode.Password) {
- View messageArea = mView.findViewById(R.id.keyguard_message_area);
- top += messageArea.getTop();
- }
- return top;
- }
-
- public boolean handleBackKey() {
- SecurityMode securityMode = mKeyguardSecurityContainerController.getCurrentSecurityMode();
- if (securityMode != SecurityMode.None) {
- mKeyguardSecurityContainerController.dismiss(
- false, KeyguardUpdateMonitor.getCurrentUser(), securityMode);
- return true;
- }
- return false;
- }
-
- /**
- * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
- * some cases where we wish to disable it, notably when the menu button placement or technology
- * is prone to false positives.
- *
- * @return true if the menu key should be enabled
- */
- public boolean shouldEnableMenuKey() {
- final Resources res = mView.getResources();
- final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
- final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
- final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
- return !configDisabled || isTestHarness || fileOverride;
- }
-
- /**
- * @return true if the current bouncer is password
- */
- public boolean dispatchBackKeyEventPreIme() {
- if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
- == SecurityMode.Password) {
- return true;
- }
- return false;
- }
-
- /**
- * @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
- */
- @NonNull
- public OnBackAnimationCallback getBackCallback() {
- return mKeyguardSecurityContainerController.getBackCallback();
- }
-
- /**
- * Allows the media keys to work when the keyguard is showing.
- * The media keys should be of no interest to the actual keyguard view(s),
- * so intercepting them here should not be of any harm.
- * @param event The key event
- * @return whether the event was consumed as a media key.
- */
- public boolean interceptMediaKey(KeyEvent event) {
- int keyCode = event.getKeyCode();
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAY/PAUSE toggle when phone is ringing or
- * in-call to avoid music playback */
- if (mTelephonyManager != null &&
- mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
- return true; // suppress key event
- }
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
- handleMediaKeyEvent(event);
- return true;
- }
-
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_MUTE: {
- if (KEYGUARD_MANAGES_VOLUME) {
- // Volume buttons should only function for music (local or remote).
- // TODO: Actually handle MUTE.
- mAudioManager.adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER /* direction */,
- AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
- // Don't execute default volume behavior
- return true;
- } else {
- return false;
- }
- }
- }
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
- handleMediaKeyEvent(event);
- return true;
- }
- }
- }
- return false;
- }
-
-
- private void handleMediaKeyEvent(KeyEvent keyEvent) {
- mAudioManager.dispatchMediaKeyEvent(keyEvent);
- }
-
- public void finish(boolean strongAuth, int currentUser) {
- mSecurityCallback.finish(strongAuth, currentUser);
- }
-
- /**
- * Apply keyguard configuration from the currently active resources. This can be called when the
- * device configuration changes, to re-apply some resources that are qualified on the device
- * configuration.
- */
- public void updateResources() {
- int gravity;
-
- Resources resources = mView.getResources();
-
- if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
- gravity = resources.getInteger(
- R.integer.keyguard_host_view_one_handed_gravity);
- } else {
- gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
- }
-
- mTranslationY = resources
- .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
- // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
- // We're just changing the gravity here though (which can't be applied to RelativeLayout),
- // so only attempt the update if mView is inside a FrameLayout.
- if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
- if (lp.gravity != gravity) {
- lp.gravity = gravity;
- mView.setLayoutParams(lp);
- }
- }
-
- if (mKeyguardSecurityContainerController != null) {
- mKeyguardSecurityContainerController.updateResources();
- }
- }
-
- /** Update keyguard position based on a tapped X coordinate. */
- public void updateKeyguardPosition(float x) {
- if (mKeyguardSecurityContainerController != null) {
- mKeyguardSecurityContainerController.updateKeyguardPosition(x);
- }
- }
-
- /** Set true if the view can be interacted with */
- public void setInteractable(boolean isInteractable) {
- mView.setInteractable(isInteractable);
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 48844db..bec8547 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -52,26 +52,7 @@
// The following is used to ignore callbacks from SecurityViews that are no longer current
// (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
// state for the current security method.
- private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
- @Override
- public void userActivity() { }
- @Override
- public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
- @Override
- public boolean isVerifyUnlockOnly() {
- return false;
- }
- @Override
- public void dismiss(boolean securityVerified, int targetUserId,
- SecurityMode expectedSecurityMode) { }
- @Override
- public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
- @Override
- public void onUserInput() { }
- @Override
- public void reset() {}
- };
+ private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {};
protected KeyguardInputViewController(T view, SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index bc72f79..bf9c3bb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -25,7 +25,9 @@
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param expectedSecurityMode The security mode that is invoking this dismiss.
*/
- void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode);
+ default void dismiss(boolean securityVerified, int targetUserId,
+ SecurityMode expectedSecurityMode) {
+ }
/**
* Dismiss the given security screen.
@@ -35,19 +37,26 @@
* if any, during this dismissal.
* @param expectedSecurityMode The security mode that is invoking this dismiss.
*/
- void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen,
- SecurityMode expectedSecurityMode);
+ default boolean dismiss(boolean securityVerified, int targetUserId,
+ boolean bypassSecondaryLockScreen,
+ SecurityMode expectedSecurityMode) {
+ return false;
+ }
/**
* Manually report user activity to keep the device awake.
*/
- void userActivity();
+ default void userActivity() {
+ }
/**
* Checks if keyguard is in "verify credentials" mode.
+ *
* @return true if user has been asked to verify security.
*/
- boolean isVerifyUnlockOnly();
+ default boolean isVerifyUnlockOnly() {
+ return false;
+ }
/**
* Call to report an unlock attempt.
@@ -56,12 +65,14 @@
* @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
* Only nonzero if 'success' is false
*/
- void reportUnlockAttempt(int userId, boolean success, int timeoutMs);
+ default void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
+ }
/**
* Resets the keyguard view.
*/
- void reset();
+ default void reset() {
+ }
/**
* Call when cancel button is pressed in bouncer.
@@ -73,5 +84,19 @@
/**
* Invoked whenever users are typing their password or drawing a pattern.
*/
- void onUserInput();
+ default void onUserInput() {
+ }
+
+
+ /**
+ * Dismisses keyguard and go to unlocked state.
+ */
+ default void finish(boolean strongAuth, int targetUserId) {
+ }
+
+ /**
+ * Specifies that security mode has changed.
+ */
+ default void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9f07a20..eec788b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -50,6 +50,7 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BlendMode;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -164,6 +165,8 @@
private boolean mDisappearAnimRunning;
private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode();
+ private boolean mIsInteractable;
+ protected ViewMediatorCallback mViewMediatorCallback;
/*
* Using MODE_UNINITIALIZED to mean the view mode is set to DefaultViewMode, but init() has not
* yet been called on it. This will happen when the ViewController is initialized.
@@ -265,31 +268,6 @@
return mBackCallback;
}
- // Used to notify the container when something interesting happens.
- public interface SecurityCallback {
- /**
- * Potentially dismiss the current security screen, after validating that all device
- * security has been unlocked. Otherwise show the next screen.
- */
- boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen,
- SecurityMode expectedSecurityMode);
-
- void userActivity();
-
- void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
-
- /**
- * @param strongAuth wheher the user has authenticated with strong authentication like
- * pattern, password or PIN but not by trust agents or fingerprint
- * @param targetUserId a user that needs to be the foreground user at the finish completion.
- */
- void finish(boolean strongAuth, int targetUserId);
-
- void reset();
-
- void onCancelClicked();
- }
-
public interface SwipeListener {
void onSwipeUp();
}
@@ -342,7 +320,7 @@
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
+ mSpringAnimation = new SpringAnimation(this, DynamicAnimation.TRANSLATION_Y);
mViewConfiguration = ViewConfiguration.get(context);
mDoubleTapDetector = new GestureDetector(context, new DoubleTapListener());
}
@@ -445,6 +423,11 @@
mViewMode.reset();
}
+ /** Set true if the view can be interacted with */
+ public void setInteractable(boolean isInteractable) {
+ mIsInteractable = isInteractable;
+ }
+
@Override
public boolean shouldDelayChildPressedState() {
return true;
@@ -452,6 +435,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (!mIsInteractable) {
+ return true;
+ }
+
boolean result = mMotionEventListeners.stream().anyMatch(
listener -> listener.onInterceptTouchEvent(event))
|| super.onInterceptTouchEvent(event);
@@ -639,6 +626,18 @@
return insets.inset(0, 0, 0, inset);
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.keyguardDoneDrawing();
+ }
+ }
+
+ public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
+ mViewMediatorCallback = viewMediatorCallback;
+ }
+
private void showDialog(String title, String message) {
if (mAlertDialog != null) {
mAlertDialog.dismiss();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b135652..23f887e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -29,18 +29,27 @@
import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.biometrics.BiometricSourceType;
+import android.media.AudioManager;
import android.metrics.LogMaker;
+import android.os.SystemClock;
import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.util.Log;
+import android.util.MathUtils;
import android.util.Slog;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
import android.window.OnBackAnimationCallback;
import androidx.annotation.NonNull;
@@ -54,7 +63,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
@@ -68,6 +76,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.log.SessionTracker;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -76,6 +85,7 @@
import com.android.systemui.util.ViewController;
import com.android.systemui.util.settings.GlobalSettings;
+import java.io.File;
import java.util.Optional;
import javax.inject.Inject;
@@ -96,7 +106,6 @@
private final UiEventLogger mUiEventLogger;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
- private final SecurityCallback mSecurityCallback;
private final ConfigurationController mConfigurationController;
private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager;
@@ -106,6 +115,20 @@
private final SessionTracker mSessionTracker;
private final Optional<SideFpsController> mSideFpsController;
private final FalsingA11yDelegate mFalsingA11yDelegate;
+ private int mTranslationY;
+ // Whether the volume keys should be handled by keyguard. If true, then
+ // they will be handled here for specific media types such as music, otherwise
+ // the audio service will bring up the volume dialog.
+ private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+
+ private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+
+ private final TelephonyManager mTelephonyManager;
+ private final ViewMediatorCallback mViewMediatorCallback;
+ private final AudioManager mAudioManager;
+ private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
+ private ActivityStarter.OnDismissAction mDismissAction;
+ private Runnable mCancelAction;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -150,11 +173,6 @@
};
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
- public void userActivity() {
- if (mSecurityCallback != null) {
- mSecurityCallback.userActivity();
- }
- }
@Override
public void onUserInput() {
@@ -169,16 +187,23 @@
}
@Override
- public void dismiss(boolean authenticated, int targetId,
+ public boolean dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
- mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
- expectedSecurityMode);
+ return showNextSecurityScreenOrFinish(
+ authenticated, targetId, bypassSecondaryLockScreen, expectedSecurityMode);
}
+ @Override
+ public void userActivity() {
+ mViewMediatorCallback.userActivity();
+ }
+
+ @Override
public boolean isVerifyUnlockOnly() {
return false;
}
+ @Override
public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
int bouncerSide = SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__SIDE__DEFAULT;
if (mView.isSidedSecurityMode()) {
@@ -215,12 +240,47 @@
: BouncerUiEvent.BOUNCER_PASSWORD_FAILURE, getSessionId());
}
+ @Override
public void reset() {
- mSecurityCallback.reset();
+ mViewMediatorCallback.resetKeyguard();
}
+ @Override
public void onCancelClicked() {
- mSecurityCallback.onCancelClicked();
+ mViewMediatorCallback.onCancelClicked();
+ }
+
+ /**
+ * Authentication has happened and it's time to dismiss keyguard. This function
+ * should clean up and inform KeyguardViewMediator.
+ *
+ * @param strongAuth whether the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
+ * @param targetUserId a user that needs to be the foreground user at the dismissal
+ * completion.
+ */
+ @Override
+ public void finish(boolean strongAuth, int targetUserId) {
+ // If there's a pending runnable because the user interacted with a widget
+ // and we're leaving keyguard, then run it.
+ boolean deferKeyguardDone = false;
+ if (mDismissAction != null) {
+ deferKeyguardDone = mDismissAction.onDismiss();
+ mDismissAction = null;
+ mCancelAction = null;
+ }
+ if (mViewMediatorCallback != null) {
+ if (deferKeyguardDone) {
+ mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
+ } else {
+ mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
+ }
+ }
+ }
+
+ @Override
+ public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+ mViewMediatorCallback.setNeedsInput(needsInput);
}
};
@@ -265,6 +325,34 @@
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
+ public void onTrustGrantedForCurrentUser(
+ boolean dismissKeyguard,
+ boolean newlyUnlocked,
+ TrustGrantFlags flags,
+ String message
+ ) {
+ if (dismissKeyguard) {
+ if (!mView.isVisibleToUser()) {
+ // The trust agent dismissed the keyguard without the user proving
+ // that they are present (by swiping up to show the bouncer). That's
+ // fine if the user proved presence via some other way to the trust
+ // agent.
+ Log.i(TAG, "TrustAgent dismissed Keyguard.");
+ }
+ mKeyguardSecurityCallback.dismiss(
+ false /* authenticated */,
+ KeyguardUpdateMonitor.getCurrentUser(),
+ /* bypassSecondaryLockScreen */ false,
+ SecurityMode.Invalid
+ );
+ } else {
+ if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
+ mViewMediatorCallback.playTrustedSound();
+ }
+ }
+ }
+
+ @Override
public void onDevicePolicyManagerStateChanged() {
showPrimarySecurityScreen(false);
}
@@ -283,7 +371,8 @@
}
};
- private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
+ @Inject
+ public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -291,7 +380,6 @@
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
- SecurityCallback securityCallback,
KeyguardSecurityViewFlipperController securityViewFlipperController,
ConfigurationController configurationController,
FalsingCollector falsingCollector,
@@ -301,7 +389,11 @@
GlobalSettings globalSettings,
SessionTracker sessionTracker,
Optional<SideFpsController> sideFpsController,
- FalsingA11yDelegate falsingA11yDelegate) {
+ FalsingA11yDelegate falsingA11yDelegate,
+ TelephonyManager telephonyManager,
+ ViewMediatorCallback viewMediatorCallback,
+ AudioManager audioManager
+ ) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -309,7 +401,6 @@
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
- mSecurityCallback = securityCallback;
mSecurityViewFlipperController = securityViewFlipperController;
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
mKeyguardSecurityCallback);
@@ -323,11 +414,15 @@
mSessionTracker = sessionTracker;
mSideFpsController = sideFpsController;
mFalsingA11yDelegate = falsingA11yDelegate;
+ mTelephonyManager = telephonyManager;
+ mViewMediatorCallback = viewMediatorCallback;
+ mAudioManager = audioManager;
}
@Override
public void onInit() {
mSecurityViewFlipperController.init();
+ updateResources();
configureMode();
}
@@ -338,6 +433,11 @@
mView.addMotionEventListener(mGlobalTouchListener);
mConfigurationController.addCallback(mConfigurationListener);
mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback);
+ mView.setViewMediatorCallback(mViewMediatorCallback);
+ // Update ViewMediator with the current input method requirements
+ mViewMediatorCallback.setNeedsInput(needsInput());
+ mView.setOnKeyListener(mOnKeyListener);
+ showPrimarySecurityScreen(false);
}
@Override
@@ -350,6 +450,11 @@
/** */
public void onPause() {
+ if (DEBUG) {
+ Log.d(TAG, String.format("screen off, instance %s at %s",
+ Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+ }
+ showPrimarySecurityScreen(true);
mAdminSecondaryLockScreenController.hide();
if (mCurrentSecurityMode != SecurityMode.None) {
getCurrentSecurityController().onPause();
@@ -358,6 +463,7 @@
// It might happen that onStartingToHide is not called when the device is locked while on
// bouncer.
setBouncerVisible(false);
+ mView.clearFocus();
}
private void updateSideFpsVisibility() {
@@ -394,12 +500,22 @@
* @param turningOff true if the device is being turned off
*/
public void showPrimarySecurityScreen(boolean turningOff) {
+ if (DEBUG) Log.d(TAG, "show()");
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser()));
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
showSecurityScreen(securityMode);
}
+ /**
+ * Show a string explaining why the security view needs to be solved.
+ *
+ * @param reason a flag indicating which string should be shown, see
+ * {@link KeyguardSecurityView#PROMPT_REASON_NONE},
+ * {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
+ * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
+ * {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
+ */
@Override
public void showPromptReason(int reason) {
if (mCurrentSecurityMode != SecurityMode.None) {
@@ -416,8 +532,32 @@
}
}
- public SecurityMode getCurrentSecurityMode() {
- return mCurrentSecurityMode;
+ /**
+ * Sets an action to run when keyguard finishes.
+ *
+ * @param action callback to be invoked when keyguard disappear animation completes.
+ */
+ public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
+ if (mCancelAction != null) {
+ mCancelAction.run();
+ mCancelAction = null;
+ }
+ mDismissAction = action;
+ mCancelAction = cancelAction;
+ }
+
+ /**
+ * @return whether dismiss action or cancel action has been set.
+ */
+ public boolean hasDismissActions() {
+ return mDismissAction != null || mCancelAction != null;
+ }
+
+ /**
+ * Remove any dismiss action or cancel action that was set.
+ */
+ public void cancelDismissAction() {
+ setOnDismissAction(null, null);
}
/**
@@ -429,17 +569,64 @@
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
}
+ /**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
+ * @return True if the keyguard is done.
+ */
+ public boolean dismiss(int targetUserId) {
+ return mKeyguardSecurityCallback.dismiss(false, targetUserId, false,
+ getCurrentSecurityMode());
+ }
+
+ public SecurityMode getCurrentSecurityMode() {
+ return mCurrentSecurityMode;
+ }
+
+ /**
+ * @return the top of the corresponding view.
+ */
+ public int getTop() {
+ int top = mView.getTop();
+ // The password view has an extra top padding that should be ignored.
+ if (getCurrentSecurityMode() == SecurityMode.Password) {
+ View messageArea = mView.findViewById(R.id.keyguard_message_area);
+ top += messageArea.getTop();
+ }
+ return top;
+ }
+
+ /** Set true if the view can be interacted with */
+ public void setInteractable(boolean isInteractable) {
+ mView.setInteractable(isInteractable);
+ }
+
+ /**
+ * Dismiss keyguard due to a user unlock event.
+ */
+ public void finish(boolean strongAuth, int currentUser) {
+ mKeyguardSecurityCallback.finish(strongAuth, currentUser);
+ }
+
+ /**
+ * @return the text of the KeyguardMessageArea.
+ */
+ public CharSequence getTitle() {
+ return mView.getTitle();
+ }
+
+ /**
+ * Resets the state of the views.
+ */
public void reset() {
mView.reset();
mSecurityViewFlipperController.reset();
}
- public CharSequence getTitle() {
- return mView.getTitle();
- }
-
@Override
public void onResume(int reason) {
+ if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+ mView.requestFocus();
if (mCurrentSecurityMode != SecurityMode.None) {
int state = SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN;
if (mView.isSidedSecurityMode()) {
@@ -457,6 +644,25 @@
mKeyguardStateController.isFaceAuthEnabled());
}
+ /**
+ * Show the bouncer and start appear animations.
+ *
+ */
+ public void appear() {
+ // We might still be collapsed and the view didn't have time to layout yet or still
+ // be small, let's wait on the predraw to do the animation in that case.
+ mView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mView.getViewTreeObserver().removeOnPreDrawListener(this);
+ startAppearAnimation();
+ return true;
+ }
+ });
+ mView.requestLayout();
+ }
+
public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) {
mView.setAlpha(1f);
@@ -466,12 +672,19 @@
}
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
+ boolean didRunAnimation = false;
+
if (mCurrentSecurityMode != SecurityMode.None) {
mView.startDisappearAnimation(mCurrentSecurityMode);
- return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable);
+ didRunAnimation = getCurrentSecurityController().startDisappearAnimation(
+ onFinishRunnable);
}
- return false;
+ if (!didRunAnimation && onFinishRunnable != null) {
+ onFinishRunnable.run();
+ }
+
+ return didRunAnimation;
}
public void onStartingToHide() {
@@ -586,7 +799,7 @@
mUiEventLogger.log(uiEvent, getSessionId());
}
if (finish) {
- mSecurityCallback.finish(strongAuth, targetUserId);
+ mKeyguardSecurityCallback.finish(strongAuth, targetUserId);
}
return finish;
}
@@ -599,11 +812,114 @@
* @return the {@link OnBackAnimationCallback} to animate this view during a back gesture.
*/
@NonNull
- OnBackAnimationCallback getBackCallback() {
+ public OnBackAnimationCallback getBackCallback() {
return mView.getBackCallback();
}
/**
+ * @return whether we should dispatch the back key event before Ime.
+ */
+ public boolean dispatchBackKeyEventPreIme() {
+ return getCurrentSecurityMode() == SecurityMode.Password;
+ }
+
+ /**
+ * Allows the media keys to work when the keyguard is showing.
+ * The media keys should be of no interest to the actual keyguard view(s),
+ * so intercepting them here should not be of any harm.
+ * @param event The key event
+ * @return whether the event was consumed as a media key.
+ */
+ public boolean interceptMediaKey(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or
+ * in-call to avoid music playback */
+ if (mTelephonyManager != null
+ && mTelephonyManager.getCallState()
+ != TelephonyManager.CALL_STATE_IDLE) {
+ return true; // suppress key event
+ }
+ return false;
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ handleMediaKeyEvent(event);
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE: {
+ if (KEYGUARD_MANAGES_VOLUME) {
+ // Volume buttons should only function for music (local or remote).
+ // TODO: Actually handle MUTE.
+ mAudioManager.adjustSuggestedStreamVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? AudioManager.ADJUST_RAISE
+ : AudioManager.ADJUST_LOWER /* direction */,
+ AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
+ // Don't execute default volume behavior
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ handleMediaKeyEvent(event);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private void handleMediaKeyEvent(KeyEvent keyEvent) {
+ mAudioManager.dispatchMediaKeyEvent(keyEvent);
+ }
+
+ /**
+ * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+ * some cases where we wish to disable it, notably when the menu button placement or technology
+ * is prone to false positives.
+ *
+ * @return true if the menu key should be enabled
+ */
+ public boolean shouldEnableMenuKey() {
+ final Resources res = mView.getResources();
+ final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+ final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+ final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+ return !configDisabled || isTestHarness || fileOverride;
+ }
+
+
+ /**
* Switches to the given security view unless it's already being shown, in which case
* this is a no-op.
*
@@ -631,7 +947,7 @@
configureMode();
}
- mSecurityCallback.onSecurityModeChanged(
+ mKeyguardSecurityCallback.onSecurityModeChanged(
securityMode, newView != null && newView.needsInput());
}
@@ -729,6 +1045,30 @@
* configuration.
*/
public void updateResources() {
+ int gravity;
+
+ Resources resources = mView.getResources();
+
+ if (resources.getBoolean(R.bool.can_use_one_handed_bouncer)) {
+ gravity = resources.getInteger(
+ R.integer.keyguard_host_view_one_handed_gravity);
+ } else {
+ gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
+ }
+
+ mTranslationY = resources
+ .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
+ // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
+ // We're just changing the gravity here though (which can't be applied to RelativeLayout),
+ // so only attempt the update if mView is inside a FrameLayout.
+ if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
+ if (lp.gravity != gravity) {
+ lp.gravity = gravity;
+ mView.setLayoutParams(lp);
+ }
+ }
+
int newOrientation = getResources().getConfiguration().orientation;
if (newOrientation != mLastOrientation) {
mLastOrientation = newOrientation;
@@ -765,77 +1105,15 @@
mKeyguardSecurityCallback);
}
- static class Factory {
-
- private final KeyguardSecurityContainer mView;
- private final AdminSecondaryLockScreenController.Factory
- mAdminSecondaryLockScreenControllerFactory;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardSecurityModel mKeyguardSecurityModel;
- private final MetricsLogger mMetricsLogger;
- private final UiEventLogger mUiEventLogger;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
- private final ConfigurationController mConfigurationController;
- private final FalsingCollector mFalsingCollector;
- private final FalsingManager mFalsingManager;
- private final GlobalSettings mGlobalSettings;
- private final FeatureFlags mFeatureFlags;
- private final UserSwitcherController mUserSwitcherController;
- private final SessionTracker mSessionTracker;
- private final Optional<SideFpsController> mSidefpsController;
- private final FalsingA11yDelegate mFalsingA11yDelegate;
-
- @Inject
- Factory(KeyguardSecurityContainer view,
- AdminSecondaryLockScreenController.Factory
- adminSecondaryLockScreenControllerFactory,
- LockPatternUtils lockPatternUtils,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardSecurityModel keyguardSecurityModel,
- MetricsLogger metricsLogger,
- UiEventLogger uiEventLogger,
- KeyguardStateController keyguardStateController,
- KeyguardSecurityViewFlipperController securityViewFlipperController,
- ConfigurationController configurationController,
- FalsingCollector falsingCollector,
- FalsingManager falsingManager,
- UserSwitcherController userSwitcherController,
- FeatureFlags featureFlags,
- GlobalSettings globalSettings,
- SessionTracker sessionTracker,
- Optional<SideFpsController> sidefpsController,
- FalsingA11yDelegate falsingA11yDelegate) {
- mView = view;
- mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
- mLockPatternUtils = lockPatternUtils;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mKeyguardSecurityModel = keyguardSecurityModel;
- mMetricsLogger = metricsLogger;
- mUiEventLogger = uiEventLogger;
- mKeyguardStateController = keyguardStateController;
- mSecurityViewFlipperController = securityViewFlipperController;
- mConfigurationController = configurationController;
- mFalsingCollector = falsingCollector;
- mFalsingManager = falsingManager;
- mFeatureFlags = featureFlags;
- mGlobalSettings = globalSettings;
- mUserSwitcherController = userSwitcherController;
- mSessionTracker = sessionTracker;
- mSidefpsController = sidefpsController;
- mFalsingA11yDelegate = falsingA11yDelegate;
- }
-
- public KeyguardSecurityContainerController create(
- SecurityCallback securityCallback) {
- return new KeyguardSecurityContainerController(mView,
- mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
- mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
- mConfigurationController, mFalsingCollector, mFalsingManager,
- mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
- mSidefpsController, mFalsingA11yDelegate);
- }
+ /**
+ * Fades and translates in/out the security screen.
+ * Fades in as expansion approaches 0.
+ * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
+ * @param fraction amount of the screen that should show.
+ */
+ public void setExpansion(float fraction) {
+ float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
+ mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+ mView.setTranslationY(scaledFraction * mTranslationY);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5b628f8..addae72 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1942,11 +1942,23 @@
FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_STARTED_WAKING_UP);
- requestActiveUnlock(
+
+ final ActiveUnlockConfig.ActiveUnlockRequestOrigin requestOrigin =
mActiveUnlockConfig.isWakeupConsideredUnlockIntent(pmWakeReason)
? ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT
- : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
- "wakingUp - " + PowerManager.wakeReasonToString(pmWakeReason));
+ : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE;
+ final String reason = "wakingUp - " + PowerManager.wakeReasonToString(pmWakeReason);
+ if (mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(pmWakeReason)) {
+ requestActiveUnlockDismissKeyguard(
+ requestOrigin,
+ reason
+ );
+ } else {
+ requestActiveUnlock(
+ requestOrigin,
+ reason
+ );
+ }
} else {
mLogger.logSkipUpdateFaceListeningOnWakeup(pmWakeReason);
}
@@ -2606,6 +2618,7 @@
}
}
+
/**
* Attempts to trigger active unlock from trust agent.
* Only dismisses the keyguard under certain conditions.
@@ -2648,6 +2661,7 @@
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"alternateBouncer");
}
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
private boolean shouldTriggerActiveUnlock() {
@@ -2732,7 +2746,7 @@
|| shouldListenForFingerprintAssistant
|| (mKeyguardOccluded && mIsDreaming)
|| (mKeyguardOccluded && userDoesNotHaveTrust
- && (mOccludingAppRequestingFp || isUdfps));
+ && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing));
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -2773,6 +2787,7 @@
System.currentTimeMillis(),
user,
shouldListen,
+ mAlternateBouncerShowing,
biometricEnabledForUser,
mPrimaryBouncerIsOrWillBeShowing,
userCanSkipBouncer,
@@ -3803,7 +3818,7 @@
}
// TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
- // (KeyguardViewMediator, KeyguardHostView)
+ // (KeyguardViewMediator, KeyguardSecurityContainer)
/**
* Dispatch wakeup events to:
* - update biometric listening states
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 413a3ca..bfd99d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -468,6 +468,17 @@
}
}
+ /**
+ * @return whether the userUnlockedWithBiometric state changed
+ */
+ private boolean updateUserUnlockedWithBiometric() {
+ final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
+ mUserUnlockedWithBiometric =
+ mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
+ KeyguardUpdateMonitor.getCurrentUser());
+ return wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric;
+ }
+
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -505,11 +516,7 @@
@Override
public void onBiometricsCleared() {
- final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
- if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric) {
+ if (updateUserUnlockedWithBiometric()) {
updateVisibility();
}
}
@@ -518,10 +525,8 @@
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
final boolean wasRunningFps = mRunningFPS;
- final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
+ final boolean userUnlockedWithBiometricChanged =
+ updateUserUnlockedWithBiometric();
if (biometricSourceType == FINGERPRINT) {
mRunningFPS = running;
@@ -539,8 +544,7 @@
}
}
- if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric
- || wasRunningFps != mRunningFPS) {
+ if (userUnlockedWithBiometricChanged || wasRunningFps != mRunningFPS) {
updateVisibility();
}
}
@@ -551,6 +555,7 @@
@Override
public void onUnlockedChanged() {
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+ updateUserUnlockedWithBiometric();
updateKeyguardShowing();
updateVisibility();
}
@@ -568,9 +573,7 @@
updateKeyguardShowing();
if (mIsKeyguardShowing) {
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
+ updateUserUnlockedWithBiometric();
}
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 5ad21df..154b0ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -18,7 +18,7 @@
import android.view.ViewGroup;
-import com.android.keyguard.KeyguardHostViewController;
+import com.android.keyguard.KeyguardSecurityContainerController;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
@@ -37,6 +37,6 @@
KeyguardBouncerComponent create(@BindsInstance @RootView ViewGroup bouncerContainer);
}
- /** Returns a {@link KeyguardHostViewController}. */
- KeyguardHostViewController getKeyguardHostViewController();
+ /** Returns a {@link KeyguardSecurityContainerController}. */
+ KeyguardSecurityContainerController getSecurityContainerController();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index cb7a0a9..38f252a 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -23,7 +23,6 @@
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardSecurityContainer;
import com.android.keyguard.KeyguardSecurityViewFlipper;
import com.android.systemui.R;
@@ -47,19 +46,13 @@
/** */
@Provides
@KeyguardBouncerScope
- static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView,
+ static KeyguardSecurityContainer providesKeyguardSecurityContainer(@RootView ViewGroup rootView,
LayoutInflater layoutInflater) {
- KeyguardHostView hostView = (KeyguardHostView) layoutInflater.inflate(
- R.layout.keyguard_host_view, rootView, false);
- rootView.addView(hostView);
- return hostView;
- }
-
- /** */
- @Provides
- @KeyguardBouncerScope
- static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) {
- return hostView.findViewById(R.id.keyguard_security_container);
+ KeyguardSecurityContainer securityContainer =
+ (KeyguardSecurityContainer) layoutInflater.inflate(
+ R.layout.keyguard_security_container_view, rootView, false);
+ rootView.addView(securityContainer);
+ return securityContainer;
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
index 621b99d..6721c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
@@ -31,6 +31,7 @@
import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
import com.android.systemui.people.widget.PeopleBackupHelper
+import com.android.systemui.settings.UserFileManagerImpl
/**
* Helper for backing up elements in SystemUI
@@ -58,17 +59,8 @@
override fun onCreate(userHandle: UserHandle, operationType: Int) {
super.onCreate()
- // The map in mapOf is guaranteed to be order preserving
- val controlsMap = mapOf(CONTROLS to getPPControlsFile(this))
- NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
- addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
- }
- // Conversations widgets backup only works for system user, because widgets' information is
- // stored in system user's SharedPreferences files and we can't open those from other users.
- if (!userHandle.isSystem) {
- return
- }
+ addControlsHelper(userHandle.identifier)
val keys = PeopleBackupHelper.getFilesToBackup()
addHelper(
@@ -95,6 +87,18 @@
sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
}
+ private fun addControlsHelper(userId: Int) {
+ val file = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = CONTROLS,
+ )
+ // The map in mapOf is guaranteed to be order preserving
+ val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId))
+ NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
+ addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
+ }
+ }
+
/**
* Helper class for restoring files ONLY if they are not present.
*
@@ -136,17 +140,21 @@
}
}
-private fun getPPControlsFile(context: Context): () -> Unit {
+private fun getPPControlsFile(context: Context, userId: Int): () -> Unit {
return {
- val filesDir = context.filesDir
- val file = Environment.buildPath(filesDir, BackupHelper.CONTROLS)
+ val file = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = BackupHelper.CONTROLS,
+ )
if (file.exists()) {
- val dest =
- Environment.buildPath(filesDir, AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
+ val dest = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
+ )
file.copyTo(dest)
val jobScheduler = context.getSystemService(JobScheduler::class.java)
jobScheduler?.schedule(
- AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
+ AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index c8cf5d7..e698faf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -134,7 +134,6 @@
private float mScaleFactor = 1f;
// sensor locations without any resolution scaling nor rotation adjustments:
@Nullable private final Point mFaceSensorLocationDefault;
- @Nullable private final Point mFingerprintSensorLocationDefault;
// cached sensor locations:
@Nullable private Point mFaceSensorLocation;
@Nullable private Point mFingerprintSensorLocation;
@@ -595,11 +594,23 @@
@Nullable private Point getFingerprintSensorLocationInNaturalOrientation() {
if (getUdfpsLocation() != null) {
return getUdfpsLocation();
+ } else {
+ int xFpLocation = mCachedDisplayInfo.getNaturalWidth() / 2;
+ try {
+ xFpLocation = mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen
+ .physical_fingerprint_sensor_center_screen_location_x);
+ } catch (Resources.NotFoundException e) {
+ }
+
+ return new Point(
+ (int) (xFpLocation * mScaleFactor),
+ (int) (mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen
+ .physical_fingerprint_sensor_center_screen_location_y)
+ * mScaleFactor)
+ );
}
- return new Point(
- (int) (mFingerprintSensorLocationDefault.x * mScaleFactor),
- (int) (mFingerprintSensorLocationDefault.y * mScaleFactor)
- );
}
/**
@@ -778,19 +789,6 @@
}
mDisplay = mContext.getDisplay();
- mDisplay.getDisplayInfo(mCachedDisplayInfo);
- int xFpLocation = mCachedDisplayInfo.getNaturalWidth() / 2;
- try {
- xFpLocation = mContext.getResources().getDimensionPixelSize(
- com.android.systemui.R.dimen
- .physical_fingerprint_sensor_center_screen_location_x);
- } catch (Resources.NotFoundException e) {
- }
- mFingerprintSensorLocationDefault = new Point(
- xFpLocation,
- mContext.getResources().getDimensionPixelSize(com.android.systemui.R.dimen
- .physical_fingerprint_sensor_center_screen_location_y)
- );
updateSensorLocations();
IntentFilter filter = new IntentFilter();
@@ -1265,7 +1263,6 @@
pw.println(" mScaleFactor=" + mScaleFactor);
pw.println(" faceAuthSensorLocationDefault=" + mFaceSensorLocationDefault);
pw.println(" faceAuthSensorLocation=" + getFaceSensorLocation());
- pw.println(" fingerprintSensorLocationDefault=" + mFingerprintSensorLocationDefault);
pw.println(" fingerprintSensorLocationInNaturalOrientation="
+ getFingerprintSensorLocationInNaturalOrientation());
pw.println(" fingerprintSensorLocation=" + getFingerprintSensorLocation());
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
index 2e2970f..9847c10 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
@@ -22,7 +22,9 @@
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
import com.android.systemui.dagger.SysUISingleton
import kotlin.math.cos
+import kotlin.math.pow
import kotlin.math.sin
+import kotlin.math.sqrt
private enum class SensorPixelPosition {
OUTSIDE, // Pixel that falls outside of sensor circle
@@ -40,6 +42,11 @@
@SysUISingleton
class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : OverlapDetector {
override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
+ // First, check if entire ellipse is within the sensor
+ if (isEllipseWithinSensor(touchData, nativeSensorBounds)) {
+ return true
+ }
+
var isTargetTouched = false
var sensorPixels = 0
var coveredPixels = 0
@@ -112,4 +119,28 @@
return result <= 1
}
+
+ /** Returns whether the entire ellipse is contained within the sensor area */
+ private fun isEllipseWithinSensor(
+ touchData: NormalizedTouchData,
+ nativeSensorBounds: Rect
+ ): Boolean {
+ val a2 = (touchData.minor / 2.0).pow(2.0)
+ val b2 = (touchData.major / 2.0).pow(2.0)
+
+ val sin2a = sin(touchData.orientation.toDouble()).pow(2.0)
+ val cos2a = cos(touchData.orientation.toDouble()).pow(2.0)
+
+ val cx = sqrt(a2 * cos2a + b2 * sin2a)
+ val cy = sqrt(a2 * sin2a + b2 * cos2a)
+
+ val ellipseRect =
+ Rect(
+ (-cx + touchData.x).toInt(),
+ (-cy + touchData.y).toInt(),
+ (cx + touchData.x).toInt(),
+ (cy + touchData.y).toInt()
+ )
+ return nativeSensorBounds.contains(ellipseRect)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
index 0a6335e..b3c18fb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
@@ -21,8 +21,10 @@
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
+import android.os.PersistableBundle
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.backup.BackupHelper
+import com.android.systemui.settings.UserFileManagerImpl
import java.io.File
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
@@ -33,14 +35,14 @@
* This file is a copy of the `controls_favorites.xml` file restored from a back up. It is used to
* keep track of controls that were restored but its corresponding app has not been installed yet.
*/
-class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor(
- wrapper: ControlsFavoritePersistenceWrapper
-) {
+class AuxiliaryPersistenceWrapper
+@VisibleForTesting
+internal constructor(wrapper: ControlsFavoritePersistenceWrapper) {
constructor(
file: File,
executor: Executor
- ): this(ControlsFavoritePersistenceWrapper(file, executor))
+ ) : this(ControlsFavoritePersistenceWrapper(file, executor))
companion object {
const val AUXILIARY_FILE_NAME = "aux_controls_favorites.xml"
@@ -48,9 +50,7 @@
private var persistenceWrapper: ControlsFavoritePersistenceWrapper = wrapper
- /**
- * Access the current list of favorites as tracked by the auxiliary file
- */
+ /** Access the current list of favorites as tracked by the auxiliary file */
var favorites: List<StructureInfo> = emptyList()
private set
@@ -73,18 +73,19 @@
* exist, it will be initialized to an empty list.
*/
fun initialize() {
- favorites = if (persistenceWrapper.fileExists) {
- persistenceWrapper.readFavorites()
- } else {
- emptyList()
- }
+ favorites =
+ if (persistenceWrapper.fileExists) {
+ persistenceWrapper.readFavorites()
+ } else {
+ emptyList()
+ }
}
/**
* Gets the list of favorite controls as persisted in the auxiliary file for a given component.
*
- * When the favorites for that application are returned, they will be removed from the
- * auxiliary file immediately, so they won't be retrieved again.
+ * When the favorites for that application are returned, they will be removed from the auxiliary
+ * file immediately, so they won't be retrieved again.
* @param componentName the name of the service that provided the controls
* @return a list of structures with favorites
*/
@@ -103,20 +104,20 @@
}
}
- /**
- * [JobService] to delete the auxiliary file after a week.
- */
+ /** [JobService] to delete the auxiliary file after a week. */
class DeletionJobService : JobService() {
companion object {
- @VisibleForTesting
- internal val DELETE_FILE_JOB_ID = 1000
+ @VisibleForTesting internal val DELETE_FILE_JOB_ID = 1000
+ @VisibleForTesting internal val USER = "USER"
private val WEEK_IN_MILLIS = TimeUnit.DAYS.toMillis(7)
- fun getJobForContext(context: Context): JobInfo {
+ fun getJobForContext(context: Context, targetUserId: Int): JobInfo {
val jobId = DELETE_FILE_JOB_ID + context.userId
val componentName = ComponentName(context, DeletionJobService::class.java)
+ val bundle = PersistableBundle().also { it.putInt(USER, targetUserId) }
return JobInfo.Builder(jobId, componentName)
.setMinimumLatency(WEEK_IN_MILLIS)
.setPersisted(true)
+ .setExtras(bundle)
.build()
}
}
@@ -127,8 +128,14 @@
}
override fun onStartJob(params: JobParameters): Boolean {
+ val userId = params.getExtras()?.getInt(USER, 0) ?: 0
synchronized(BackupHelper.controlsDataLock) {
- baseContext.deleteFile(AUXILIARY_FILE_NAME)
+ val file =
+ UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = AUXILIARY_FILE_NAME,
+ )
+ baseContext.deleteFile(file.getPath())
}
return false
}
@@ -137,4 +144,4 @@
return true // reschedule and try again if the job was stopped without completing
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index ad5ad13..9921b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -32,6 +32,7 @@
import com.android.systemui.dreams.AssistantAttentionMonitor
import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
+import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
@@ -294,6 +295,11 @@
@ClassKey(StylusUsiPowerStartable::class)
abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
+ @Binds
+ @IntoMap
+ @ClassKey(PhysicalKeyboardCoreStartable::class)
+ abstract fun bindKeyboardCoreStartable(listener: PhysicalKeyboardCoreStartable): CoreStartable
+
/** Inject into MuteQuickAffordanceCoreStartable*/
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a1050ec..f6bb85f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -48,6 +48,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.keyboard.KeyboardModule;
import com.android.systemui.keyguard.data.BouncerViewModule;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
@@ -151,6 +152,7 @@
SystemPropertiesFlagsModule.class,
FooterActionsModule.class,
GarbageMonitorModule.class,
+ KeyboardModule.class,
LogModule.class,
MediaProjectionModule.class,
MotionToolModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
index dc7fc28..06ca0ad 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -22,6 +22,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.InitializationChecker
+import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -36,7 +37,9 @@
private val flagCommand: FlagCommand,
private val featureFlags: FeatureFlagsDebug,
private val broadcastSender: BroadcastSender,
- private val initializationChecker: InitializationChecker
+ private val initializationChecker: InitializationChecker,
+ private val restartDozeListener: RestartDozeListener,
+ private val delayableExecutor: DelayableExecutor
) : CoreStartable {
init {
@@ -52,6 +55,9 @@
// protected broadcast should only be sent for the main process
val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
broadcastSender.sendBroadcast(intent)
+
+ restartDozeListener.init()
+ delayableExecutor.executeDelayed({ restartDozeListener.maybeRestartSleep() }, 1000)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
index d088d74..133e67f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
@@ -18,6 +18,8 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.InitializationChecker
+import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -26,7 +28,13 @@
class FeatureFlagsReleaseStartable
@Inject
-constructor(dumpManager: DumpManager, featureFlags: FeatureFlags) : CoreStartable {
+constructor(
+ dumpManager: DumpManager,
+ featureFlags: FeatureFlags,
+ private val initializationChecker: InitializationChecker,
+ private val restartDozeListener: RestartDozeListener,
+ private val delayableExecutor: DelayableExecutor
+) : CoreStartable {
init {
dumpManager.registerCriticalDumpable(FeatureFlagsRelease.TAG) { pw, args ->
@@ -35,7 +43,10 @@
}
override fun start() {
- // no-op
+ if (initializationChecker.initializeComponents()) {
+ restartDozeListener.init()
+ delayableExecutor.executeDelayed({ restartDozeListener.maybeRestartSleep() }, 1000)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d328f87..da59996 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -260,6 +260,11 @@
// TODO(b/244064524): Tracking Bug
@JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag(508, "qs_secondary_data_sub_info")
+ /** Enables Font Scaling Quick Settings tile */
+ // TODO(b/269341316): Tracking Bug
+ @JvmField
+ val ENABLE_FONT_SCALING_TILE = unreleasedFlag(509, "enable_font_scaling_tile", teamfood = false)
+
// 600- status bar
// TODO(b/256614753): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt
new file mode 100644
index 0000000..bd74f4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.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.flags
+
+import android.os.PowerManager
+import android.util.Log
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+
+@SysUISingleton
+class RestartDozeListener
+@Inject
+constructor(
+ private val settings: SecureSettings,
+ private val statusBarStateController: StatusBarStateController,
+ private val powerManager: PowerManager,
+ private val systemClock: SystemClock,
+) {
+
+ companion object {
+ @VisibleForTesting val RESTART_NAP_KEY = "restart_nap_after_start"
+ }
+
+ private var inited = false
+
+ val listener =
+ object : StatusBarStateController.StateListener {
+ override fun onDreamingChanged(isDreaming: Boolean) {
+ settings.putBool(RESTART_NAP_KEY, isDreaming)
+ }
+ }
+
+ fun init() {
+ if (inited) {
+ return
+ }
+ inited = true
+
+ statusBarStateController.addCallback(listener)
+ }
+
+ fun destroy() {
+ statusBarStateController.removeCallback(listener)
+ }
+
+ fun maybeRestartSleep() {
+ if (settings.getBool(RESTART_NAP_KEY, false)) {
+ Log.d("RestartDozeListener", "Restarting sleep state")
+ powerManager.wakeUp(systemClock.uptimeMillis())
+ powerManager.goToSleep(systemClock.uptimeMillis())
+ settings.putBool(RESTART_NAP_KEY, false)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
index e225b10..7acd3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
@@ -62,11 +62,10 @@
return
}
-
for ((listener, flags) in listeners) {
propLoop@ for (propName in properties.keyset) {
for (flag in flags) {
- if (propName == getServerOverrideName(flag.id) || propName == flag.name) {
+ if (propName == flag.name) {
listener.onChange(flag)
break@propLoop
}
@@ -103,10 +102,6 @@
}
listeners.add(Pair(listener, flags))
}
-
- private fun getServerOverrideName(flagId: Int): String {
- return "flag_override_$flagId"
- }
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
new file mode 100644
index 0000000..e9b8908
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.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.keyboard
+
+import dagger.Module
+
+@Module abstract class KeyboardModule
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
new file mode 100644
index 0000000..b0f9c4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.keyboard
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+
+/** A [CoreStartable] that launches components interested in physical keyboard interaction. */
+@SysUISingleton
+class PhysicalKeyboardCoreStartable
+@Inject
+constructor(
+ private val featureFlags: FeatureFlags,
+) : CoreStartable {
+ override fun start() {
+ if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
+ // TODO(b/268645743) start listening for keyboard backlight brightness
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2fb53f1..0ca9115 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -928,7 +928,7 @@
}
// The smartspace is not visible if the bouncer is showing, so don't shared element it.
- if (keyguardStateController.isBouncerShowing) {
+ if (keyguardStateController.isPrimaryBouncerShowing) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c5ea241..54fc5b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1150,12 +1150,12 @@
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
@Override
- public void onBouncerShowingChanged() {
+ public void onPrimaryBouncerShowingChanged() {
synchronized (KeyguardViewMediator.this) {
- if (mKeyguardStateController.isBouncerShowing()) {
+ if (mKeyguardStateController.isPrimaryBouncerShowing()) {
mPendingPinLock = false;
}
- adjustStatusBarLocked(mKeyguardStateController.isBouncerShowing(), false);
+ adjustStatusBarLocked(mKeyguardStateController.isPrimaryBouncerShowing(), false);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 091acad..4331fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -68,8 +68,8 @@
val resourceUpdateRequests: StateFlow<Boolean>
val bouncerPromptReason: Int
val bouncerErrorMessage: CharSequence?
- val isAlternateBouncerVisible: StateFlow<Boolean>
- val isAlternateBouncerUIAvailable: StateFlow<Boolean>
+ val alternateBouncerVisible: StateFlow<Boolean>
+ val alternateBouncerUIAvailable: StateFlow<Boolean>
var lastAlternateBouncerVisibleTime: Long
fun setPrimaryScrimmed(isScrimmed: Boolean)
@@ -159,12 +159,12 @@
get() = viewMediatorCallback.consumeCustomMessage()
/** Values associated with the AlternateBouncer */
- private val _isAlternateBouncerVisible = MutableStateFlow(false)
- override val isAlternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
+ private val _alternateBouncerVisible = MutableStateFlow(false)
+ override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
override var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE
- private val _isAlternateBouncerUIAvailable = MutableStateFlow(false)
- override val isAlternateBouncerUIAvailable: StateFlow<Boolean> =
- _isAlternateBouncerUIAvailable.asStateFlow()
+ private val _alternateBouncerUIAvailable = MutableStateFlow(false)
+ override val alternateBouncerUIAvailable: StateFlow<Boolean> =
+ _alternateBouncerUIAvailable.asStateFlow()
init {
setUpLogging()
@@ -179,16 +179,16 @@
}
override fun setAlternateVisible(isVisible: Boolean) {
- if (isVisible && !_isAlternateBouncerVisible.value) {
+ if (isVisible && !_alternateBouncerVisible.value) {
lastAlternateBouncerVisibleTime = clock.uptimeMillis()
} else if (!isVisible) {
lastAlternateBouncerVisibleTime = NOT_VISIBLE
}
- _isAlternateBouncerVisible.value = isVisible
+ _alternateBouncerVisible.value = isVisible
}
override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
- _isAlternateBouncerUIAvailable.value = isAvailable
+ _alternateBouncerUIAvailable.value = isAvailable
}
override fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) {
@@ -290,7 +290,7 @@
resourceUpdateRequests
.logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
.launchIn(applicationScope)
- isAlternateBouncerUIAvailable
+ alternateBouncerUIAvailable
.logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false)
.launchIn(applicationScope)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt
new file mode 100644
index 0000000..2069891
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt
@@ -0,0 +1,342 @@
+/*
+ * 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 android.app.StatusBarManager
+import android.content.Context
+import android.hardware.face.FaceManager
+import android.os.CancellationSignal
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.FaceAuthUiEvent
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.AuthenticationStatus
+import com.android.systemui.keyguard.shared.model.DetectionStatus
+import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
+import com.android.systemui.log.FaceAuthenticationLogger
+import com.android.systemui.log.SessionTracker
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.user.data.repository.UserRepository
+import java.io.PrintWriter
+import java.util.Arrays
+import java.util.stream.Collectors
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * API to run face authentication and detection for device entry / on keyguard (as opposed to the
+ * biometric prompt).
+ */
+interface KeyguardFaceAuthManager {
+ /**
+ * 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]
+ */
+ suspend fun authenticate(uiEvent: FaceAuthUiEvent)
+
+ /**
+ * Trigger face detection.
+ *
+ * Invocation should be ignored if face authentication is currently running.
+ */
+ suspend fun detect()
+
+ /** Stop currently running face authentication or detection. */
+ fun cancel()
+
+ /** Provide the current status of face authentication. */
+ val authenticationStatus: Flow<AuthenticationStatus>
+
+ /** Provide the current status of face detection. */
+ val detectionStatus: Flow<DetectionStatus>
+
+ /** Current state of whether face authentication is locked out or not. */
+ val isLockedOut: Flow<Boolean>
+
+ /** Current state of whether face authentication is running. */
+ val isAuthRunning: Flow<Boolean>
+
+ /** Is face detection supported. */
+ val isDetectionSupported: Boolean
+}
+
+@SysUISingleton
+class KeyguardFaceAuthManagerImpl
+@Inject
+constructor(
+ context: Context,
+ private val faceManager: FaceManager? = null,
+ private val userRepository: UserRepository,
+ private val keyguardBypassController: KeyguardBypassController? = null,
+ @Application private val applicationScope: CoroutineScope,
+ @Main private val mainDispatcher: CoroutineDispatcher,
+ private val sessionTracker: SessionTracker,
+ private val uiEventsLogger: UiEventLogger,
+ private val faceAuthLogger: FaceAuthenticationLogger,
+ dumpManager: DumpManager,
+) : KeyguardFaceAuthManager, Dumpable {
+ private var cancellationSignal: CancellationSignal? = null
+ private val lockscreenBypassEnabled: Boolean
+ get() = keyguardBypassController?.bypassEnabled ?: false
+ private var faceAcquiredInfoIgnoreList: Set<Int>
+
+ private val faceLockoutResetCallback =
+ object : FaceManager.LockoutResetCallback() {
+ override fun onLockoutReset(sensorId: Int) {
+ _isLockedOut.value = false
+ }
+ }
+
+ init {
+ faceManager?.addLockoutResetCallback(faceLockoutResetCallback)
+ faceAcquiredInfoIgnoreList =
+ Arrays.stream(
+ context.resources.getIntArray(
+ R.array.config_face_acquire_device_entry_ignorelist
+ )
+ )
+ .boxed()
+ .collect(Collectors.toSet())
+ dumpManager.registerCriticalDumpable("KeyguardFaceAuthManagerImpl", this)
+ }
+
+ private val faceAuthCallback =
+ object : FaceManager.AuthenticationCallback() {
+ override fun onAuthenticationFailed() {
+ _authenticationStatus.value = FailedAuthenticationStatus
+ faceAuthLogger.authenticationFailed()
+ onFaceAuthRequestCompleted()
+ }
+
+ override fun onAuthenticationAcquired(acquireInfo: Int) {
+ _authenticationStatus.value = AcquiredAuthenticationStatus(acquireInfo)
+ faceAuthLogger.authenticationAcquired(acquireInfo)
+ }
+
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
+ val errorStatus = ErrorAuthenticationStatus(errorCode, errString.toString())
+ if (errorStatus.isLockoutError()) {
+ _isLockedOut.value = true
+ }
+ _authenticationStatus.value = errorStatus
+ if (errorStatus.isCancellationError()) {
+ cancelNotReceivedHandlerJob?.cancel()
+ applicationScope.launch {
+ faceAuthLogger.launchingQueuedFaceAuthRequest(
+ faceAuthRequestedWhileCancellation
+ )
+ faceAuthRequestedWhileCancellation?.let { authenticate(it) }
+ faceAuthRequestedWhileCancellation = null
+ }
+ }
+ faceAuthLogger.authenticationError(
+ errorCode,
+ errString,
+ errorStatus.isLockoutError(),
+ errorStatus.isCancellationError()
+ )
+ onFaceAuthRequestCompleted()
+ }
+
+ override fun onAuthenticationHelp(code: Int, helpStr: CharSequence?) {
+ if (faceAcquiredInfoIgnoreList.contains(code)) {
+ return
+ }
+ _authenticationStatus.value = HelpAuthenticationStatus(code, helpStr.toString())
+ }
+
+ override fun onAuthenticationSucceeded(result: FaceManager.AuthenticationResult) {
+ _authenticationStatus.value = SuccessAuthenticationStatus(result)
+ faceAuthLogger.faceAuthSuccess(result)
+ onFaceAuthRequestCompleted()
+ }
+ }
+
+ private fun onFaceAuthRequestCompleted() {
+ cancellationInProgress = false
+ _isAuthRunning.value = false
+ cancellationSignal = null
+ }
+
+ private val detectionCallback =
+ FaceManager.FaceDetectionCallback { sensorId, userId, isStrong ->
+ faceAuthLogger.faceDetected()
+ _detectionStatus.value = DetectionStatus(sensorId, userId, isStrong)
+ }
+
+ private var cancellationInProgress = false
+ private var faceAuthRequestedWhileCancellation: FaceAuthUiEvent? = null
+
+ override suspend fun authenticate(uiEvent: FaceAuthUiEvent) {
+ if (_isAuthRunning.value) {
+ faceAuthLogger.ignoredFaceAuthTrigger(uiEvent)
+ return
+ }
+
+ if (cancellationInProgress) {
+ faceAuthLogger.queuingRequestWhileCancelling(
+ faceAuthRequestedWhileCancellation,
+ uiEvent
+ )
+ faceAuthRequestedWhileCancellation = uiEvent
+ return
+ } else {
+ faceAuthRequestedWhileCancellation = null
+ }
+
+ withContext(mainDispatcher) {
+ // We always want to invoke face auth in the main thread.
+ cancellationSignal = CancellationSignal()
+ _isAuthRunning.value = true
+ uiEventsLogger.logWithInstanceIdAndPosition(
+ uiEvent,
+ 0,
+ null,
+ keyguardSessionId,
+ uiEvent.extraInfo
+ )
+ faceAuthLogger.authenticating(uiEvent)
+ faceManager?.authenticate(
+ null,
+ cancellationSignal,
+ faceAuthCallback,
+ null,
+ currentUserId,
+ lockscreenBypassEnabled
+ )
+ }
+ }
+
+ override suspend fun detect() {
+ if (!isDetectionSupported) {
+ faceAuthLogger.detectionNotSupported(faceManager, faceManager?.sensorPropertiesInternal)
+ return
+ }
+ if (_isAuthRunning.value) {
+ faceAuthLogger.skippingBecauseAlreadyRunning("detection")
+ return
+ }
+
+ cancellationSignal = CancellationSignal()
+ withContext(mainDispatcher) {
+ // We always want to invoke face detect in the main thread.
+ faceAuthLogger.faceDetectionStarted()
+ faceManager?.detectFace(cancellationSignal, detectionCallback, currentUserId)
+ }
+ }
+
+ private val currentUserId: Int
+ get() = userRepository.getSelectedUserInfo().id
+
+ override fun cancel() {
+ if (cancellationSignal == null) return
+
+ cancellationSignal?.cancel()
+ cancelNotReceivedHandlerJob =
+ applicationScope.launch {
+ delay(DEFAULT_CANCEL_SIGNAL_TIMEOUT)
+ faceAuthLogger.cancelSignalNotReceived(
+ _isAuthRunning.value,
+ _isLockedOut.value,
+ cancellationInProgress,
+ faceAuthRequestedWhileCancellation
+ )
+ onFaceAuthRequestCompleted()
+ }
+ cancellationInProgress = true
+ _isAuthRunning.value = false
+ }
+
+ private var cancelNotReceivedHandlerJob: Job? = null
+
+ private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> =
+ MutableStateFlow(null)
+ override val authenticationStatus: Flow<AuthenticationStatus>
+ get() = _authenticationStatus.filterNotNull()
+
+ private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null)
+ override val detectionStatus: Flow<DetectionStatus>
+ get() = _detectionStatus.filterNotNull()
+
+ private val _isLockedOut = MutableStateFlow(false)
+ override val isLockedOut: Flow<Boolean> = _isLockedOut
+
+ override val isDetectionSupported =
+ faceManager?.sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection ?: false
+
+ private val _isAuthRunning = MutableStateFlow(false)
+ override val isAuthRunning: Flow<Boolean>
+ get() = _isAuthRunning
+
+ private val keyguardSessionId: InstanceId?
+ get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD)
+
+ companion object {
+ const val TAG = "KeyguardFaceAuthManager"
+
+ /**
+ * If no cancel signal has been received after this amount of time, assume that it is
+ * cancelled.
+ */
+ const val DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000L
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("KeyguardFaceAuthManagerImpl state:")
+ pw.println(" cancellationInProgress: $cancellationInProgress")
+ pw.println(" _isLockedOut.value: ${_isLockedOut.value}")
+ pw.println(" _isAuthRunning.value: ${_isAuthRunning.value}")
+ pw.println(" isDetectionSupported: $isDetectionSupported")
+ pw.println(" FaceManager state:")
+ pw.println(" faceManager: $faceManager")
+ pw.println(" sensorPropertiesInternal: ${faceManager?.sensorPropertiesInternal}")
+ pw.println(
+ " supportsFaceDetection: " +
+ "${faceManager?.sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection}"
+ )
+ pw.println(
+ " faceAuthRequestedWhileCancellation: ${faceAuthRequestedWhileCancellation?.reason}"
+ )
+ pw.println(" cancellationSignal: $cancellationSignal")
+ pw.println(" faceAcquiredInfoIgnoreList: $faceAcquiredInfoIgnoreList")
+ pw.println(" _authenticationStatus: ${_authenticationStatus.value}")
+ pw.println(" _detectionStatus: ${_detectionStatus.value}")
+ pw.println(" currentUserId: $currentUserId")
+ pw.println(" keyguardSessionId: $keyguardSessionId")
+ pw.println(" lockscreenBypassEnabled: $lockscreenBypassEnabled")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index db95562..a3b3d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -86,9 +86,6 @@
/** Observable for the signal that keyguard is about to go away. */
val isKeyguardGoingAway: Flow<Boolean>
- /** Observable for whether the bouncer is showing. */
- val isBouncerShowing: Flow<Boolean>
-
/** Is the always-on display available to be used? */
val isAodAvailable: Flow<Boolean>
@@ -304,29 +301,6 @@
awaitClose { keyguardStateController.removeCallback(callback) }
}
- override val isBouncerShowing: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onBouncerShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isBouncerShowing,
- TAG,
- "updated isBouncerShowing"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isBouncerShowing,
- TAG,
- "initial isBouncerShowing"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
-
override val isDozing: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
index 0e865ce..fa6efa5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -29,16 +29,9 @@
) :
SharedPreferencesBackupHelper(
context,
- if (UserFileManagerImpl.isPrimaryUser(userId)) {
- KeyguardQuickAffordanceSelectionManager.FILE_NAME
- } else {
- UserFileManagerImpl.secondaryUserFile(
- context = context,
- fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
- directoryName = UserFileManagerImpl.SHARED_PREFS,
- userId = userId,
- )
- .also { UserFileManagerImpl.ensureParentDirExists(it) }
- .toString()
- }
+ UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
+ )
+ .getPath()
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 6452e0e..dfe1038 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -44,7 +44,7 @@
var legacyAlternateBouncer: LegacyAlternateBouncer? = null
var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE
- val isVisible: Flow<Boolean> = bouncerRepository.isAlternateBouncerVisible
+ val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
/**
* Sets the correct bouncer states to show the alternate bouncer if it can show.
@@ -86,7 +86,7 @@
fun isVisibleState(): Boolean {
return if (isModernAlternateBouncerEnabled) {
- bouncerRepository.isAlternateBouncerVisible.value
+ bouncerRepository.alternateBouncerVisible.value
} else {
legacyAlternateBouncer?.isShowingAlternateBouncer ?: false
}
@@ -98,7 +98,7 @@
fun canShowAlternateBouncerForFingerprint(): Boolean {
return if (isModernAlternateBouncerEnabled) {
- bouncerRepository.isAlternateBouncerUIAvailable.value &&
+ bouncerRepository.alternateBouncerUIAvailable.value &&
biometricSettingsRepository.isFingerprintEnrolled.value &&
biometricSettingsRepository.isStrongBiometricAllowed.value &&
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
new file mode 100644
index 0000000..310f44d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -0,0 +1,158 @@
+/*
+ * 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.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class FromAlternateBouncerTransitionInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) : TransitionInteractor(FromAlternateBouncerTransitionInteractor::class.simpleName!!) {
+
+ override fun start() {
+ listenForAlternateBouncerToGone()
+ listenForAlternateBouncerToLockscreenAodOrDozing()
+ listenForAlternateBouncerToPrimaryBouncer()
+ }
+
+ private fun listenForAlternateBouncerToLockscreenAodOrDozing() {
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing
+ // Add a slight delay, as alternateBouncer and primaryBouncer showing event changes
+ // will arrive with a small gap in time. This prevents a transition to LOCKSCREEN
+ // happening prematurely.
+ .onEach { delay(50) }
+ .sample(
+ combine(
+ keyguardInteractor.primaryBouncerShowing,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ keyguardInteractor.wakefulnessModel,
+ keyguardInteractor.isAodAvailable,
+ ::toQuad
+ ),
+ ::toQuint
+ )
+ .collect {
+ (
+ isAlternateBouncerShowing,
+ isPrimaryBouncerShowing,
+ lastStartedTransitionStep,
+ wakefulnessState,
+ isAodAvailable
+ ) ->
+ if (
+ !isAlternateBouncerShowing &&
+ !isPrimaryBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.ALTERNATE_BOUNCER
+ ) {
+ val to =
+ if (
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
+ wakefulnessState.state == WakefulnessState.ASLEEP
+ ) {
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ }
+ } else {
+ KeyguardState.LOCKSCREEN
+ }
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = to,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForAlternateBouncerToGone() {
+ scope.launch {
+ keyguardInteractor.isKeyguardGoingAway
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .collect { (isKeyguardGoingAway, keyguardState) ->
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.GONE,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForAlternateBouncerToPrimaryBouncer() {
+ scope.launch {
+ keyguardInteractor.primaryBouncerShowing
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
+ if (
+ isPrimaryBouncerShowing &&
+ startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun getAnimator(): ValueAnimator {
+ return ValueAnimator().apply {
+ interpolator = Interpolators.LINEAR
+ duration = TRANSITION_DURATION_MS
+ }
+ }
+
+ companion object {
+ private const val TRANSITION_DURATION_MS = 300L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 5674e2a..d01f489 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -33,7 +33,6 @@
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -53,9 +52,10 @@
listenForLockscreenToOccluded()
listenForLockscreenToCamera()
listenForLockscreenToAodOrDozing()
- listenForLockscreenToBouncer()
+ listenForLockscreenToPrimaryBouncer()
listenForLockscreenToDreaming()
- listenForLockscreenToBouncerDragging()
+ listenForLockscreenToPrimaryBouncerDragging()
+ listenForLockscreenToAlternateBouncer()
}
private fun listenForLockscreenToDreaming() {
@@ -78,9 +78,9 @@
}
}
- private fun listenForLockscreenToBouncer() {
+ private fun listenForLockscreenToPrimaryBouncer() {
scope.launch {
- keyguardInteractor.isBouncerShowing
+ keyguardInteractor.primaryBouncerShowing
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
@@ -91,7 +91,30 @@
TransitionInfo(
ownerName = name,
from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForLockscreenToAlternateBouncer() {
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { pair ->
+ val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair
+ if (
+ isAlternateBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
animator = getAnimator(),
)
)
@@ -101,7 +124,7 @@
}
/* Starts transitions when manually dragging up the bouncer from the lockscreen. */
- private fun listenForLockscreenToBouncerDragging() {
+ private fun listenForLockscreenToPrimaryBouncerDragging() {
var transitionId: UUID? = null
scope.launch {
shadeRepository.shadeModel
@@ -144,7 +167,7 @@
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.LOCKSCREEN,
animator = getAnimator(0.milliseconds)
)
@@ -163,7 +186,7 @@
TransitionInfo(
ownerName = name,
from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
animator = null,
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
similarity index 75%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 0e9c447..b59b413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -24,62 +24,63 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
-import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
-import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
-class FromBouncerTransitionInteractor
+class FromPrimaryBouncerTransitionInteractor
@Inject
constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val shadeRepository: ShadeRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor
-) : TransitionInteractor(FromBouncerTransitionInteractor::class.simpleName!!) {
-
- private var transitionId: UUID? = null
+) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
override fun start() {
- listenForBouncerToGone()
- listenForBouncerToLockscreenOrAod()
+ listenForPrimaryBouncerToGone()
+ listenForPrimaryBouncerToLockscreenAodOrDozing()
}
- private fun listenForBouncerToLockscreenOrAod() {
+ private fun listenForPrimaryBouncerToLockscreenAodOrDozing() {
scope.launch {
- keyguardInteractor.isBouncerShowing
+ keyguardInteractor.primaryBouncerShowing
.sample(
combine(
keyguardInteractor.wakefulnessModel,
keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
+ keyguardInteractor.isAodAvailable,
+ ::toTriple
),
- ::toTriple
+ ::toQuad
)
- .collect { triple ->
- val (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) = triple
+ .collect {
+ (isBouncerShowing, wakefulnessState, lastStartedTransitionStep, isAodAvailable)
+ ->
if (
- !isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.BOUNCER
+ !isBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
) {
val to =
if (
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
wakefulnessState.state == WakefulnessState.ASLEEP
) {
- KeyguardState.AOD
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ }
} else {
KeyguardState.LOCKSCREEN
}
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = to,
animator = getAnimator(),
)
@@ -89,17 +90,17 @@
}
}
- private fun listenForBouncerToGone() {
+ private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
.collect { pair ->
val (isKeyguardGoingAway, keyguardState) = pair
- if (isKeyguardGoingAway && keyguardState == KeyguardState.BOUNCER) {
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
animator = getAnimator(),
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 7e86a5d..d25aff0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -24,6 +24,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -56,6 +57,7 @@
private val repository: KeyguardRepository,
private val commandQueue: CommandQueue,
featureFlags: FeatureFlags,
+ bouncerRepository: KeyguardBouncerRepository,
) {
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -121,8 +123,10 @@
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
/** Whether the keyguard is going away. */
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
- /** Whether the bouncer is showing or not. */
- val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
+ /** Whether the primary bouncer is showing or not. */
+ val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
+ /** Whether the alternate bouncer is showing or not. */
+ val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
/** The device wake/sleep state */
val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
@@ -142,12 +146,12 @@
if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
combine(
isKeyguardVisible,
- repository.isBouncerShowing,
+ bouncerRepository.primaryBouncerVisible,
onCameraLaunchDetected,
- ) { isKeyguardVisible, isBouncerShowing, cameraLaunchEvent ->
+ ) { isKeyguardVisible, isPrimaryBouncerShowing, cameraLaunchEvent ->
when {
isKeyguardVisible -> false
- isBouncerShowing -> false
+ isPrimaryBouncerShowing -> false
else -> cameraLaunchEvent == CameraLaunchSourceModel.POWER_DOUBLE_TAP
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index d4e23499..51b0277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -22,7 +22,6 @@
import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
private val TAG = KeyguardTransitionAuditLogger::class.simpleName!!
@@ -46,8 +45,14 @@
}
scope.launch {
- keyguardInteractor.isBouncerShowing.collect {
- logger.log(TAG, VERBOSE, "Bouncer showing", it)
+ keyguardInteractor.primaryBouncerShowing.collect {
+ logger.log(TAG, VERBOSE, "Primary bouncer showing", it)
+ }
+ }
+
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing.collect {
+ logger.log(TAG, VERBOSE, "Alternate bouncer showing", it)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index fbed446..efc1bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -37,13 +37,14 @@
// exhaustive
val ret =
when (it) {
- is FromBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
+ is FromPrimaryBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
is FromAodTransitionInteractor -> Log.d(TAG, "Started $it")
is FromGoneTransitionInteractor -> Log.d(TAG, "Started $it")
is FromLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
is FromDreamingTransitionInteractor -> Log.d(TAG, "Started $it")
is FromOccludedTransitionInteractor -> Log.d(TAG, "Started $it")
is FromDozingTransitionInteractor -> Log.d(TAG, "Started $it")
+ is FromAlternateBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
}
it.start()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 84bcdf9..1b7da5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -21,13 +21,12 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -63,9 +62,9 @@
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
- /** LOCKSCREEN->BOUNCER transition information. */
- val lockscreenToBouncerTransition: Flow<TransitionStep> =
- repository.transition(LOCKSCREEN, BOUNCER)
+ /** LOCKSCREEN->PRIMARY_BOUNCER transition information. */
+ val mLockscreenToPrimaryBouncerTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, PRIMARY_BOUNCER)
/** LOCKSCREEN->DREAMING transition information. */
val lockscreenToDreamingTransition: Flow<TransitionStep> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
index a59c407..833eda7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -86,7 +86,8 @@
KeyguardState.DOZING -> false
KeyguardState.AOD -> false
KeyguardState.DREAMING -> true
- KeyguardState.BOUNCER -> true
+ KeyguardState.ALTERNATE_BOUNCER -> true
+ KeyguardState.PRIMARY_BOUNCER -> true
KeyguardState.LOCKSCREEN -> true
KeyguardState.GONE -> true
KeyguardState.OCCLUDED -> true
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index 4579e37..e819da9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -156,7 +156,7 @@
} else {
DejankUtils.postAfterTraversal(showRunnable)
}
- keyguardStateController.notifyBouncerShowing(true)
+ keyguardStateController.notifyPrimaryBouncerShowing(true)
primaryBouncerCallbackInteractor.dispatchStartingToShow()
Trace.endSection()
}
@@ -173,7 +173,7 @@
}
falsingCollector.onBouncerHidden()
- keyguardStateController.notifyBouncerShowing(false /* showing */)
+ keyguardStateController.notifyPrimaryBouncerShowing(false /* showing */)
cancelShowRunnable()
repository.setPrimaryShowingSoon(false)
repository.setPrimaryVisible(false)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index 81fa233..d9690b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -32,7 +32,9 @@
@Binds
@IntoSet
- abstract fun fromBouncer(impl: FromBouncerTransitionInteractor): TransitionInteractor
+ abstract fun fromPrimaryBouncer(
+ impl: FromPrimaryBouncerTransitionInteractor
+ ): TransitionInteractor
@Binds
@IntoSet
@@ -53,4 +55,10 @@
@Binds
@IntoSet
abstract fun fromDozing(impl: FromDozingTransitionInteractor): TransitionInteractor
+
+ @Binds
+ @IntoSet
+ abstract fun fromAlternateBouncer(
+ impl: FromAlternateBouncerTransitionInteractor
+ ): TransitionInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index 4d24c14..e3e3527 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -30,7 +30,26 @@
abstract fun start()
+ fun <A, B, C> toTriple(a: A, b: B, c: C) = Triple(a, b, c)
+
fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
fun <A, B, C> toTriple(ab: Pair<A, B>, c: C) = Triple(ab.first, ab.second, c)
+
+ fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
+
+ fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) = Quad(a, bcd.first, bcd.second, bcd.third)
+
+ fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
+ Quint(a, bcde.first, bcde.second, bcde.third, bcde.fourth)
}
+
+data class Quad<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)
+
+data class Quint<A, B, C, D, E>(
+ val first: A,
+ val second: B,
+ val third: C,
+ val fourth: D,
+ val fifth: E
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
new file mode 100644
index 0000000..b1c5f8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.shared.model
+
+import android.hardware.face.FaceManager
+
+/** Authentication status provided by [com.android.keyguard.faceauth.KeyguardFaceAuthManager] */
+sealed class AuthenticationStatus
+
+/** Success authentication status. */
+data class SuccessAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) :
+ AuthenticationStatus()
+
+/** Face authentication help message. */
+data class HelpAuthenticationStatus(val msgId: Int, val msg: String?) : AuthenticationStatus()
+
+/** Face acquired message. */
+data class AcquiredAuthenticationStatus(val acquiredInfo: Int) : AuthenticationStatus()
+
+/** Face authentication failed message. */
+object FailedAuthenticationStatus : AuthenticationStatus()
+
+/** Face authentication error message */
+data class ErrorAuthenticationStatus(val msgId: Int, val msg: String?) : AuthenticationStatus() {
+ /**
+ * Method that checks if [msgId] is a lockout error. A lockout error means that face
+ * authentication is locked out.
+ */
+ fun isLockoutError() = msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT
+
+ /**
+ * Method that checks if [msgId] is a cancellation error. This means that face authentication
+ * was cancelled before it completed.
+ */
+ fun isCancellationError() = msgId == FaceManager.FACE_ERROR_CANCELED
+}
+
+/** Face detection success message. */
+data class DetectionStatus(val sensorId: Int, val userId: Int, val isStrongBiometric: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index c757986..87b4321 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -42,10 +42,15 @@
*/
AOD,
/*
- * The security screen prompt UI, containing PIN, Password, Pattern, and all FPS
- * (Fingerprint Sensor) variations, for the user to verify their credentials
+ * The security screen prompt containing UI to prompt the user to use a biometric credential
+ * (ie: fingerprint). When supported, this may show before showing the primary bouncer.
*/
- BOUNCER,
+ ALTERNATE_BOUNCER,
+ /*
+ * The security screen prompt UI, containing PIN, Password, Pattern for the user to verify their
+ * credentials.
+ */
+ PRIMARY_BOUNCER,
/*
* Device is actively displaying keyguard UI and is not in low-power mode. Device may be
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index b0c0dd7..56f911f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -22,10 +22,12 @@
import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.keyguard.KeyguardHostViewController
+import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.settingslib.Utils
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
@@ -43,52 +45,54 @@
viewModel: KeyguardBouncerViewModel,
componentFactory: KeyguardBouncerComponent.Factory
) {
- // Builds the KeyguardHostViewController from bouncer view group.
- val hostViewController: KeyguardHostViewController =
- componentFactory.create(view).keyguardHostViewController
- hostViewController.init()
+ // Builds the KeyguardSecurityContainerController from bouncer view group.
+ val securityContainerController: KeyguardSecurityContainerController =
+ componentFactory.create(view).securityContainerController
+ securityContainerController.init()
val delegate =
object : BouncerViewDelegate {
override fun isFullScreenBouncer(): Boolean {
- val mode = hostViewController.currentSecurityMode
+ val mode = securityContainerController.currentSecurityMode
return mode == KeyguardSecurityModel.SecurityMode.SimPin ||
mode == KeyguardSecurityModel.SecurityMode.SimPuk
}
override fun getBackCallback(): OnBackAnimationCallback {
- return hostViewController.backCallback
+ return securityContainerController.backCallback
}
override fun shouldDismissOnMenuPressed(): Boolean {
- return hostViewController.shouldEnableMenuKey()
+ return securityContainerController.shouldEnableMenuKey()
}
override fun interceptMediaKey(event: KeyEvent?): Boolean {
- return hostViewController.interceptMediaKey(event)
+ return securityContainerController.interceptMediaKey(event)
}
override fun dispatchBackKeyEventPreIme(): Boolean {
- return hostViewController.dispatchBackKeyEventPreIme()
+ return securityContainerController.dispatchBackKeyEventPreIme()
}
override fun showNextSecurityScreenOrFinish(): Boolean {
- return hostViewController.dismiss(KeyguardUpdateMonitor.getCurrentUser())
+ return securityContainerController.dismiss(
+ KeyguardUpdateMonitor.getCurrentUser()
+ )
}
override fun resume() {
- hostViewController.showPrimarySecurityScreen()
- hostViewController.onResume()
+ securityContainerController.showPrimarySecurityScreen(/* isTurningOff= */ false)
+ securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
}
override fun setDismissAction(
onDismissAction: ActivityStarter.OnDismissAction?,
cancelAction: Runnable?
) {
- hostViewController.setOnDismissAction(onDismissAction, cancelAction)
+ securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
}
override fun willDismissWithActions(): Boolean {
- return hostViewController.hasDismissActions()
+ return securityContainerController.hasDismissActions()
}
}
view.repeatWhenAttached {
@@ -98,38 +102,45 @@
launch {
viewModel.show.collect {
// Reset Security Container entirely.
- hostViewController.reinflateViewFlipper()
- hostViewController.showPromptReason(it.promptReason)
+ securityContainerController.reinflateViewFlipper()
+ securityContainerController.showPromptReason(it.promptReason)
it.errorMessage?.let { errorMessage ->
- hostViewController.showErrorMessage(errorMessage)
+ securityContainerController.showMessage(
+ errorMessage,
+ Utils.getColorError(view.context)
+ )
}
- hostViewController.showPrimarySecurityScreen()
- hostViewController.appear()
- hostViewController.onResume()
+ securityContainerController.showPrimarySecurityScreen(
+ /* turningOff= */ false
+ )
+ securityContainerController.appear()
+ securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
}
}
launch {
viewModel.hide.collect {
- hostViewController.cancelDismissAction()
- hostViewController.cleanUp()
- hostViewController.resetSecurityContainer()
+ securityContainerController.cancelDismissAction()
+ securityContainerController.onPause()
+ securityContainerController.reset()
}
}
launch {
- viewModel.startingToHide.collect { hostViewController.onStartingToHide() }
+ viewModel.startingToHide.collect {
+ securityContainerController.onStartingToHide()
+ }
}
launch {
viewModel.startDisappearAnimation.collect {
- hostViewController.startDisappearAnimation(it)
+ securityContainerController.startDisappearAnimation(it)
}
}
launch {
viewModel.bouncerExpansionAmount.collect { expansion ->
- hostViewController.setExpansion(expansion)
+ securityContainerController.setExpansion(expansion)
}
}
@@ -137,10 +148,8 @@
viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE }
.collect {
- hostViewController.onResume()
- view.announceForAccessibility(
- hostViewController.accessibilityTitleForCurrentMode
- )
+ securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
+ view.announceForAccessibility(securityContainerController.title)
}
}
@@ -148,39 +157,42 @@
viewModel.isBouncerVisible.collect { isVisible ->
val visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
view.visibility = visibility
- hostViewController.onBouncerVisibilityChanged(visibility)
+ securityContainerController.onBouncerVisibilityChanged(visibility)
}
}
launch {
viewModel.isInteractable.collect { isInteractable ->
- hostViewController.setInteractable(isInteractable)
+ securityContainerController.setInteractable(isInteractable)
}
}
launch {
viewModel.keyguardPosition.collect { position ->
- hostViewController.updateKeyguardPosition(position)
+ securityContainerController.updateKeyguardPosition(position)
}
}
launch {
viewModel.updateResources.collect {
- hostViewController.updateResources()
+ securityContainerController.updateResources()
viewModel.notifyUpdateResources()
}
}
launch {
viewModel.bouncerShowMessage.collect {
- hostViewController.showMessage(it.message, it.colorStateList)
+ securityContainerController.showMessage(it.message, it.colorStateList)
viewModel.onMessageShown()
}
}
launch {
viewModel.keyguardAuthenticated.collect {
- hostViewController.finish(it, KeyguardUpdateMonitor.getCurrentUser())
+ securityContainerController.finish(
+ it,
+ KeyguardUpdateMonitor.getCurrentUser()
+ )
viewModel.notifyKeyguardAuthenticated()
}
}
@@ -194,7 +206,7 @@
launch {
viewModel.screenTurnedOff.collect {
if (view.visibility == View.VISIBLE) {
- hostViewController.onPause()
+ securityContainerController.onPause()
}
}
}
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 d977f91..9aecb5d 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
@@ -171,7 +171,12 @@
}
private fun setUpClock(parentView: ViewGroup) {
- val clockChangeListener = ClockRegistry.ClockChangeListener { onClockChanged(parentView) }
+ val clockChangeListener =
+ object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() {
+ onClockChanged(parentView)
+ }
+ }
clockRegistry.registerClockChangeListener(clockChangeListener)
disposables.add(
DisposableHandle { clockRegistry.unregisterClockChangeListener(clockChangeListener) }
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
new file mode 100644
index 0000000..f7349a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -0,0 +1,181 @@
+package com.android.systemui.log
+
+import android.hardware.face.FaceManager
+import android.hardware.face.FaceSensorPropertiesInternal
+import com.android.keyguard.FaceAuthUiEvent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.dagger.FaceAuthLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.google.errorprone.annotations.CompileTimeConstant
+import javax.inject.Inject
+
+private const val TAG = "KeyguardFaceAuthManagerLog"
+
+/**
+ * Helper class for logging for [com.android.keyguard.faceauth.KeyguardFaceAuthManager]
+ *
+ * To enable logcat echoing for an entire buffer:
+ *
+ * ```
+ * adb shell settings put global systemui/buffer/KeyguardFaceAuthManagerLog <logLevel>
+ *
+ * ```
+ */
+@SysUISingleton
+class FaceAuthenticationLogger
+@Inject
+constructor(
+ @FaceAuthLog private val logBuffer: LogBuffer,
+) {
+ fun ignoredFaceAuthTrigger(uiEvent: FaceAuthUiEvent) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = uiEvent.reason },
+ {
+ "Ignoring trigger because face auth is currently running. " +
+ "Trigger reason: $str1"
+ }
+ )
+ }
+
+ fun queuingRequestWhileCancelling(
+ alreadyQueuedRequest: FaceAuthUiEvent?,
+ newRequest: FaceAuthUiEvent
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = alreadyQueuedRequest?.reason
+ str2 = newRequest.reason
+ },
+ {
+ "Face auth requested while previous request is being cancelled, " +
+ "already queued request: $str1 queueing the new request: $str2"
+ }
+ )
+ }
+
+ fun authenticating(uiEvent: FaceAuthUiEvent) {
+ logBuffer.log(TAG, DEBUG, { str1 = uiEvent.reason }, { "Running authenticate for $str1" })
+ }
+
+ fun detectionNotSupported(
+ faceManager: FaceManager?,
+ sensorPropertiesInternal: MutableList<FaceSensorPropertiesInternal>?
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = faceManager == null
+ bool2 = sensorPropertiesInternal.isNullOrEmpty()
+ bool2 = sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection ?: false
+ },
+ {
+ "skipping detection request because it is not supported, " +
+ "faceManager isNull: $bool1, " +
+ "sensorPropertiesInternal isNullOrEmpty: $bool2, " +
+ "supportsFaceDetection: $bool3"
+ }
+ )
+ }
+
+ fun skippingBecauseAlreadyRunning(@CompileTimeConstant operation: String) {
+ logBuffer.log(TAG, DEBUG, "isAuthRunning is true, skipping $operation")
+ }
+
+ fun faceDetectionStarted() {
+ logBuffer.log(TAG, DEBUG, "Face detection started.")
+ }
+
+ fun faceDetected() {
+ logBuffer.log(TAG, DEBUG, "Face detected")
+ }
+
+ fun cancelSignalNotReceived(
+ isAuthRunning: Boolean,
+ isLockedOut: Boolean,
+ cancellationInProgress: Boolean,
+ faceAuthRequestedWhileCancellation: FaceAuthUiEvent?
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = isAuthRunning
+ bool2 = isLockedOut
+ bool3 = cancellationInProgress
+ str1 = "${faceAuthRequestedWhileCancellation?.reason}"
+ },
+ {
+ "Cancel signal was not received, running timeout handler to reset state. " +
+ "State before reset: " +
+ "isAuthRunning: $bool1, " +
+ "isLockedOut: $bool2, " +
+ "cancellationInProgress: $bool3, " +
+ "faceAuthRequestedWhileCancellation: $str1"
+ }
+ )
+ }
+
+ fun authenticationFailed() {
+ logBuffer.log(TAG, DEBUG, "Face authentication failed")
+ }
+
+ fun authenticationAcquired(acquireInfo: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = acquireInfo },
+ { "Face acquired during face authentication: acquireInfo: $int1 " }
+ )
+ }
+
+ fun authenticationError(
+ errorCode: Int,
+ errString: CharSequence?,
+ lockoutError: Boolean,
+ cancellationError: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = errorCode
+ str1 = "$errString"
+ bool1 = lockoutError
+ bool2 = cancellationError
+ },
+ {
+ "Received authentication error: errorCode: $int1, " +
+ "errString: $str1, " +
+ "isLockoutError: $bool1, " +
+ "isCancellationError: $bool2"
+ }
+ )
+ }
+
+ fun launchingQueuedFaceAuthRequest(faceAuthRequestedWhileCancellation: FaceAuthUiEvent?) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = "${faceAuthRequestedWhileCancellation?.reason}" },
+ { "Received cancellation error and starting queued face auth request: $str1" }
+ )
+ }
+
+ fun faceAuthSuccess(result: FaceManager.AuthenticationResult) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = result.userId
+ bool1 = result.isStrongBiometric
+ },
+ { "Face authenticated successfully: userId: $int1, isStrongBiometric: $bool1" }
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/FaceAuthLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/FaceAuthLog.kt
new file mode 100644
index 0000000..b97e3a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/FaceAuthLog.kt
@@ -0,0 +1,6 @@
+package com.android.systemui.log.dagger
+
+import javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for Face authentication triggered by SysUI. */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class FaceAuthLog()
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 c02fd9c..220993f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -265,16 +265,6 @@
return factory.create("MediaCarouselCtlrLog", 20);
}
- /**
- * Provides a {@link LogBuffer} for use in the status bar connectivity pipeline
- */
- @Provides
- @SysUISingleton
- @StatusBarConnectivityLog
- public static LogBuffer provideStatusBarConnectivityBuffer(LogBufferFactory factory) {
- return factory.create("SbConnectivity", 64);
- }
-
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
@@ -360,6 +350,17 @@
}
/**
+ * Provides a {@link LogBuffer} for use by
+ * {@link com.android.keyguard.faceauth.KeyguardFaceAuthManagerImpl}.
+ */
+ @Provides
+ @SysUISingleton
+ @FaceAuthLog
+ public static LogBuffer provideFaceAuthLog(LogBufferFactory factory) {
+ return factory.create("KeyguardFaceAuthManagerLog", 300);
+ }
+
+ /**
* Provides a {@link LogBuffer} for bluetooth-related logs.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java
deleted file mode 100644
index 67cdb72..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java
+++ /dev/null
@@ -1,35 +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.log.dagger;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.plugins.log.LogBuffer;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-/**
- * A {@link LogBuffer} for status bar connectivity events.
- */
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface StatusBarConnectivityLog {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
index 146633d..95f1419 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
@@ -121,6 +121,6 @@
@Provides
@Named(PLUGIN_PRIVILEGED)
static List<String> providesPrivilegedPlugins(Context context) {
- return Arrays.asList(context.getResources().getStringArray(R.array.config_pluginWhitelist));
+ return Arrays.asList(context.getResources().getStringArray(R.array.config_pluginAllowlist));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
index bfba6df..bb637dc 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
@@ -32,74 +32,62 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.File
+import java.io.FilenameFilter
import javax.inject.Inject
/**
- * Implementation for retrieving file paths for file storage of system and secondary users. Files
- * lie in {File Directory}/UserFileManager/{User Id} for secondary user. For system user, we use the
- * conventional {File Directory}
+ * Implementation for retrieving file paths for file storage of system and secondary users. For
+ * non-system users, files will be prepended by a special prefix containing the user id.
*/
@SysUISingleton
class UserFileManagerImpl
@Inject
constructor(
- // Context of system process and system user.
private val context: Context,
val userManager: UserManager,
val broadcastDispatcher: BroadcastDispatcher,
@Background val backgroundExecutor: DelayableExecutor
) : UserFileManager, CoreStartable {
companion object {
- private const val FILES = "files"
+ private const val PREFIX = "__USER_"
+ private const val TAG = "UserFileManagerImpl"
+ const val ROOT_DIR = "UserFileManager"
+ const val FILES = "files"
const val SHARED_PREFS = "shared_prefs"
- @VisibleForTesting internal const val ID = "UserFileManager"
-
- /** Returns `true` if the given user ID is that for the primary/system user. */
- fun isPrimaryUser(userId: Int): Boolean {
- return UserHandle(userId).isSystem
- }
/**
- * Returns a [File] pointing to the correct path for a secondary user ID.
- *
- * Note that there is no check for the type of user. This should only be called for
- * secondary users, never for the system user. For that, make sure to call [isPrimaryUser].
- *
- * Note also that there is no guarantee that the parent directory structure for the file
- * exists on disk. For that, call [ensureParentDirExists].
- *
- * @param context The context
- * @param fileName The name of the file
- * @param directoryName The name of the directory that would contain the file
- * @param userId The ID of the user to build a file path for
+ * Returns a File object with a relative path, built from the userId for non-system users
*/
- fun secondaryUserFile(
- context: Context,
- fileName: String,
- directoryName: String,
- userId: Int,
- ): File {
- return Environment.buildPath(
- context.filesDir,
- ID,
- userId.toString(),
- directoryName,
- fileName,
- )
- }
-
- /**
- * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs
- * recursively.
- */
- fun ensureParentDirExists(file: File) {
- val parent = file.parentFile
- if (!parent.exists()) {
- if (!parent.mkdirs()) {
- Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}")
- }
+ fun createFile(fileName: String, userId: Int): File {
+ return if (isSystemUser(userId)) {
+ File(fileName)
+ } else {
+ File(getFilePrefix(userId) + fileName)
}
}
+
+ fun createLegacyFile(context: Context, dir: String, fileName: String, userId: Int): File? {
+ return if (isSystemUser(userId)) {
+ null
+ } else {
+ return Environment.buildPath(
+ context.filesDir,
+ ROOT_DIR,
+ userId.toString(),
+ dir,
+ fileName
+ )
+ }
+ }
+
+ fun getFilePrefix(userId: Int): String {
+ return PREFIX + userId.toString() + "_"
+ }
+
+ /** Returns `true` if the given user ID is that for the system user. */
+ private fun isSystemUser(userId: Int): Boolean {
+ return UserHandle(userId).isSystem
+ }
}
private val broadcastReceiver =
@@ -119,64 +107,87 @@
broadcastDispatcher.registerReceiver(broadcastReceiver, filter, backgroundExecutor)
}
- /** Return the file based on current user. */
+ /**
+ * Return the file based on current user. Files for all users will exist in [context.filesDir],
+ * but non system user files will be prepended with [getFilePrefix].
+ */
override fun getFile(fileName: String, userId: Int): File {
- return if (isPrimaryUser(userId)) {
- Environment.buildPath(context.filesDir, fileName)
- } else {
- val secondaryFile =
- secondaryUserFile(
- context = context,
- userId = userId,
- directoryName = FILES,
- fileName = fileName,
- )
- ensureParentDirExists(secondaryFile)
- secondaryFile
- }
+ val file = File(context.filesDir, createFile(fileName, userId).path)
+ createLegacyFile(context, FILES, fileName, userId)?.run { migrate(file, this) }
+ return file
}
- /** Get shared preferences from user. */
+ /**
+ * Get shared preferences from user. Files for all users will exist in the shared_prefs dir, but
+ * non system user files will be prepended with [getFilePrefix].
+ */
override fun getSharedPreferences(
fileName: String,
@Context.PreferencesMode mode: Int,
userId: Int
): SharedPreferences {
- if (isPrimaryUser(userId)) {
- return context.getSharedPreferences(fileName, mode)
+ val file = createFile(fileName, userId)
+ createLegacyFile(context, SHARED_PREFS, "$fileName.xml", userId)?.run {
+ val path = Environment.buildPath(context.dataDir, SHARED_PREFS, "${file.path}.xml")
+ migrate(path, this)
}
-
- val secondaryUserDir =
- secondaryUserFile(
- context = context,
- fileName = fileName,
- directoryName = SHARED_PREFS,
- userId = userId,
- )
-
- ensureParentDirExists(secondaryUserDir)
- return context.getSharedPreferences(secondaryUserDir, mode)
+ return context.getSharedPreferences(file.path, mode)
}
- /** Remove dirs for deleted users. */
+ /** Remove files for deleted users. */
@VisibleForTesting
internal fun clearDeletedUserData() {
backgroundExecutor.execute {
- val file = Environment.buildPath(context.filesDir, ID)
- if (!file.exists()) return@execute
- val aliveUsers = userManager.aliveUsers.map { it.id.toString() }
- val dirsToDelete = file.list().filter { !aliveUsers.contains(it) }
+ deleteFiles(context.filesDir)
+ deleteFiles(File(context.dataDir, SHARED_PREFS))
+ }
+ }
- dirsToDelete.forEach { dir ->
+ private fun migrate(dest: File, source: File) {
+ if (source.exists()) {
+ try {
+ val parent = source.getParentFile()
+ source.renameTo(dest)
+
+ deleteParentDirsIfEmpty(parent)
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to rename and delete ${source.path}", e)
+ }
+ }
+ }
+
+ private fun deleteParentDirsIfEmpty(dir: File?) {
+ if (dir != null && dir.listFiles().size == 0) {
+ val priorParent = dir.parentFile
+ val isRoot = dir.name == ROOT_DIR
+ dir.delete()
+
+ if (!isRoot) {
+ deleteParentDirsIfEmpty(priorParent)
+ }
+ }
+ }
+
+ private fun deleteFiles(parent: File) {
+ val aliveUserFilePrefix = userManager.aliveUsers.map { getFilePrefix(it.id) }
+ val filesToDelete =
+ parent.listFiles(
+ FilenameFilter { _, name ->
+ name.startsWith(PREFIX) &&
+ aliveUserFilePrefix.filter { name.startsWith(it) }.isEmpty()
+ }
+ )
+
+ // This can happen in test environments
+ if (filesToDelete == null) {
+ Log.i(TAG, "Empty directory: ${parent.path}")
+ } else {
+ filesToDelete.forEach { file ->
+ Log.i(TAG, "Deleting file: ${file.path}")
try {
- val dirToDelete =
- Environment.buildPath(
- file,
- dir,
- )
- dirToDelete.deleteRecursively()
+ file.delete()
} catch (e: Exception) {
- Log.e(ID, "Deletion failed.", e)
+ Log.e(TAG, "Deletion failed.", e)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index a72b7f1..1e4f5bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -49,6 +49,7 @@
}
protected int mMinimumDisplayTime;
+ protected int mStickyDisplayTime;
protected int mAutoDismissNotificationDecay;
@VisibleForTesting
public Handler mHandler;
@@ -198,7 +199,7 @@
if (entry != null && entry.isExpandAnimationRunning()) {
return;
}
-
+ entry.demoteStickyHun();
mAlertEntries.remove(key);
onAlertEntryRemoved(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -255,6 +256,15 @@
return 0;
}
+ @VisibleForTesting
+ public long getCalculatedEarliestRemovalTime(String key) {
+ AlertEntry alerting = mAlertEntries.get(key);
+ if (alerting != null) {
+ return alerting.mEarliestRemovaltime;
+ }
+ return 0;
+ }
+
protected class AlertEntry implements Comparable<AlertEntry> {
@Nullable public NotificationEntry mEntry;
public long mPostTime;
@@ -275,6 +285,11 @@
updateEntry(true /* updatePostTime */);
}
+ @VisibleForTesting
+ long getEarliestRemovaltime() {
+ return mEarliestRemovaltime;
+ }
+
/**
* Updates an entry's removal time.
* @param updatePostTime whether or not to refresh the post time
@@ -282,18 +297,22 @@
public void updateEntry(boolean updatePostTime) {
mLogger.logUpdateEntry(mEntry, updatePostTime);
- long currentTime = mClock.currentTimeMillis();
- mEarliestRemovaltime = currentTime + mMinimumDisplayTime;
+ final long now = mClock.currentTimeMillis();
+ mEarliestRemovaltime = isSticky()
+ ? mEntry.mCreationElapsedRealTime + mStickyDisplayTime
+ : now + mMinimumDisplayTime;
+
if (updatePostTime) {
- mPostTime = Math.max(mPostTime, currentTime);
+ mPostTime = Math.max(mPostTime, now);
}
removeAutoRemovalCallbacks();
- if (!isSticky()) {
- long finishTime = calculateFinishTime();
- long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
- mHandler.postDelayed(mRemoveAlertRunnable, removeDelay);
- }
+ final long finishTime = calculateFinishTime();
+ final long timeRemaining = isSticky()
+ ? finishTime - mClock.currentTimeMillis()
+ : Math.max(finishTime - now, mMinimumDisplayTime);
+
+ mHandler.postDelayed(mRemoveAlertRunnable, timeRemaining);
}
/**
@@ -302,11 +321,13 @@
* @return true if the notification is sticky
*/
public boolean isSticky() {
- return false;
+ // This implementation is overridden by HeadsUpManager HeadsUpEntry #isSticky
+ // but we keep this here for use by unit tests.
+ return mEntry.isStickyAndNotDemoted();
}
/**
- * Whether the notification has been on screen long enough and can be removed.
+ * Whether the notification has befen on screen long enough and can be removed.
* @return true if the notification has been on screen long enough
*/
public boolean wasShownLongEnough() {
@@ -355,11 +376,12 @@
}
/**
- * Calculate when the notification should auto-dismiss itself.
- * @return the finish time
+ * @return When the notification should auto-dismiss itself, based on
+ * {@link SystemClock#elapsedRealTime()}
*/
protected long calculateFinishTime() {
- return mPostTime + mAutoDismissNotificationDecay;
+ // Overridden by HeadsUpManager HeadsUpEntry #calculateFinishTime
+ return 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f565f3d..afa60fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -262,7 +262,6 @@
fun setStackScroller(nsslController: NotificationStackScrollLayoutController) {
this.nsslController = nsslController
- touchHelper.host = nsslController.view
touchHelper.expandCallback = nsslController.expandHelperCallback
}
@@ -736,14 +735,12 @@
private var dragDownAmountOnStart = 0.0f
lateinit var expandCallback: ExpandHelper.Callback
- lateinit var host: View
private var minDragDistance = 0
private var initialTouchX = 0f
private var initialTouchY = 0f
private var touchSlop = 0f
private var slopMultiplier = 0f
- private val temp2 = IntArray(2)
private var draggedFarEnough = false
private var startingChild: ExpandableView? = null
private var lastHeight = 0f
@@ -923,7 +920,6 @@
}
private fun findView(x: Float, y: Float): ExpandableView? {
- host.getLocationOnScreen(temp2)
- return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1])
+ return expandCallback.getChildAtRawPosition(x, y)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index e34096e..4e9e88d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -181,6 +181,44 @@
private boolean mBlockable;
/**
+ * The {@link SystemClock#elapsedRealtime()} when this notification entry was created.
+ */
+ public long mCreationElapsedRealTime;
+
+ /**
+ * Whether this notification has ever been a non-sticky HUN.
+ */
+ private boolean mIsDemoted = false;
+
+ /**
+ * True if both
+ * 1) app provided full screen intent but does not have the permission to send it
+ * 2) this notification has never been demoted before
+ */
+ public boolean isStickyAndNotDemoted() {
+
+ final boolean fsiRequestedButDenied = (getSbn().getNotification().flags
+ & Notification.FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
+
+ if (!fsiRequestedButDenied && !mIsDemoted) {
+ demoteStickyHun();
+ }
+ return fsiRequestedButDenied && !mIsDemoted;
+ }
+
+ @VisibleForTesting
+ public boolean isDemoted() {
+ return mIsDemoted;
+ }
+
+ /**
+ * Make sticky HUN not sticky.
+ */
+ public void demoteStickyHun() {
+ mIsDemoted = true;
+ }
+
+ /**
* @param sbn the StatusBarNotification from system server
* @param ranking also from system server
* @param creationTime SystemClock.uptimeMillis of when we were created
@@ -197,8 +235,13 @@
mKey = sbn.getKey();
setSbn(sbn);
setRanking(ranking);
+ mCreationElapsedRealTime = SystemClock.elapsedRealtime();
}
+ @VisibleForTesting
+ public void setCreationElapsedRealTime(long time) {
+ mCreationElapsedRealTime = time;
+ }
@Override
public NotificationEntry getRepresentativeEntry() {
return this;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index bc881ce..ae19feb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -33,6 +33,10 @@
/**
* Full screen intents are disabled.
*/
+ NO_FSI_SHOW_STICKY_HUN(false),
+ /**
+ * Full screen intents are disabled.
+ */
NO_FSI_DISABLED(false),
/**
* No full screen intent included, so there is nothing to show.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index afeb72f..0163dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
@@ -246,7 +247,11 @@
if (mFlags.disableFsi()) {
return FullScreenIntentDecision.NO_FSI_DISABLED;
}
+
if (entry.getSbn().getNotification().fullScreenIntent == null) {
+ if (entry.isStickyAndNotDemoted()) {
+ return FullScreenIntentDecision.NO_FSI_SHOW_STICKY_HUN;
+ }
return FullScreenIntentDecision.NO_FULL_SCREEN_INTENT;
}
@@ -335,6 +340,9 @@
final int uid = entry.getSbn().getUid();
final String packageName = entry.getSbn().getPackageName();
switch (decision) {
+ case NO_FSI_SHOW_STICKY_HUN:
+ mLogger.logNoFullscreen(entry, "Permission denied, show sticky HUN");
+ return;
case NO_FSI_DISABLED:
mLogger.logNoFullscreen(entry, "Disabled");
return;
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 79e9ff2a..7c6efe4 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
@@ -1198,6 +1198,22 @@
return getShowingLayout().getVisibleWrapper();
}
+ /**
+ * @return whether the notification row is long clickable or not.
+ */
+ public boolean isNotificationRowLongClickable() {
+ if (mLongPressListener == null) {
+ return false;
+ }
+
+ if (!areGutsExposed()) { // guts is not opened
+ return true;
+ }
+
+ // if it is leave behind, it shouldn't be long clickable.
+ return !isGutsLeaveBehind();
+ }
+
public void setLongPressListener(LongPressListener longPressListener) {
mLongPressListener = longPressListener;
}
@@ -2954,6 +2970,10 @@
return (mGuts != null && mGuts.isExposed());
}
+ private boolean isGutsLeaveBehind() {
+ return (mGuts != null && mGuts.isLeavebehind());
+ }
+
@Override
public boolean isContentExpandable() {
if (mIsSummaryWithChildren && !shouldShowPublic()) {
@@ -3401,7 +3421,12 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ final boolean isLongClickable = isNotificationRowLongClickable();
+ if (isLongClickable) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ }
+ info.setLongClickable(isLongClickable);
+
if (canViewBeDismissed() && !mIsSnoozed) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 37ff11d..06d4080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -586,7 +586,9 @@
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ if (row.isNotificationRowLongClickable()) {
+ view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
if (row.areGutsExposed()) {
closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
true /* removeControls */, -1 /* x */, -1 /* y */,
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 51125b1..46bc887 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
@@ -870,7 +870,8 @@
}
for (int i = childCount - 1; i >= 0; i--) {
- updateChildZValue(i, algorithmState, ambientState, i == topHunIndex);
+ childrenOnTop = updateChildZValue(i, childrenOnTop,
+ algorithmState, ambientState, i == topHunIndex);
}
}
@@ -880,11 +881,15 @@
*
* @param isTopHun Whether the child is a top HUN. A top HUN means a HUN that shows on the
* vertically top of screen. Top HUNs should have drop shadows
+ * @param childrenOnTop It is greater than 0 when there's an existing HUN that is elevated
+ * @return childrenOnTop The decimal part represents the fraction of the elevated HUN's height
+ * that overlaps with QQS Panel. The integer part represents the count of
+ * previous HUNs whose Z positions are greater than 0.
*/
- protected void updateChildZValue(int i,
- StackScrollAlgorithmState algorithmState,
- AmbientState ambientState,
- boolean isTopHun) {
+ protected float updateChildZValue(int i, float childrenOnTop,
+ StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState,
+ boolean isTopHun) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState childViewState = child.getViewState();
float baseZ = ambientState.getBaseZHeight();
@@ -898,16 +903,22 @@
// Handles HUN shadow when Shade is opened, and AmbientState.mScrollY > 0
// Calculate the HUN's z-value based on its overlapping fraction with QQS Panel.
// When scrolling down shade to make HUN back to in-position in Notification Panel,
- // the overlapFraction goes to 0, and the pinned HUN's shadows hides gradually.
- float overlap = ambientState.getTopPadding()
- + ambientState.getStackTranslation() - childViewState.getYTranslation();
-
- if (childViewState.height > 0) { // To avoid 0/0 problems
- // To prevent over-shadow
- float overlapFraction = MathUtils.saturate(overlap / childViewState.height);
- childViewState.setZTranslation(baseZ
- + overlapFraction * mPinnedZTranslationExtra);
+ // The over-lapping fraction goes to 0, and shadows hides gradually.
+ if (childrenOnTop != 0.0f) {
+ // To elevate the later HUN over previous HUN
+ childrenOnTop++;
+ } else {
+ float overlap = ambientState.getTopPadding()
+ + ambientState.getStackTranslation() - childViewState.getYTranslation();
+ // To prevent over-shadow during HUN entry
+ childrenOnTop += Math.min(
+ 1.0f,
+ overlap / childViewState.height
+ );
+ MathUtils.saturate(childrenOnTop);
}
+ childViewState.setZTranslation(baseZ
+ + childrenOnTop * mPinnedZTranslationExtra);
} else if (isTopHun) {
// In case this is a new view that has never been measured before, we don't want to
// elevate if we are currently expanded more than the notification
@@ -935,14 +946,15 @@
}
// Handles HUN shadow when shade is closed.
- // While shade is closed, and during HUN's entry: headerVisibleAmount stays 0, shadow stays.
- // While shade is closed, and HUN is showing: headerVisibleAmount stays 0, shadow stays.
+ // While HUN is showing and Shade is closed: headerVisibleAmount stays 0, shadow stays.
// During HUN-to-Shade (eg. dragging down HUN to open Shade): headerVisibleAmount goes
// gradually from 0 to 1, shadow hides gradually.
// Header visibility is a deprecated concept, we are using headerVisibleAmount only because
// this value nicely goes from 0 to 1 during the HUN-to-Shade process.
+
childViewState.setZTranslation(childViewState.getZTranslation()
+ (1.0f - child.getHeaderVisibleAmount()) * mPinnedZTranslationExtra);
+ return childrenOnTop;
}
public void setIsExpanded(boolean isExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 078a00d..3471a46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -27,6 +27,7 @@
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -45,6 +46,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags;
@@ -74,12 +76,14 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.wmshell.BubblesManager;
+import dagger.Lazy;
+
+import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
-import dagger.Lazy;
/**
* Status bar implementation of {@link NotificationActivityStarter}.
@@ -572,16 +576,29 @@
});
// not immersive & a fullscreen alert should be shown
- final PendingIntent fullscreenIntent =
+ final PendingIntent fullScreenIntent =
entry.getSbn().getNotification().fullScreenIntent;
- mLogger.logSendingFullScreenIntent(entry, fullscreenIntent);
+ mLogger.logSendingFullScreenIntent(entry, fullScreenIntent);
try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
entry.getKey());
mCentralSurfaces.wakeUpForFullScreenIntent();
- fullscreenIntent.send();
+ fullScreenIntent.send();
entry.notifyFullScreenIntentLaunched();
mMetricsLogger.count("note_fullscreen", 1);
+
+ String activityName;
+ List<ResolveInfo> resolveInfos = fullScreenIntent.queryIntentComponents(0);
+ if (resolveInfos.size() > 0 && resolveInfos.get(0) != null
+ && resolveInfos.get(0).activityInfo != null
+ && resolveInfos.get(0).activityInfo.name != null) {
+ activityName = resolveInfos.get(0).activityInfo.name;
+ } else {
+ activityName = "";
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
+ fullScreenIntent.getCreatorUid(),
+ activityName);
} catch (PendingIntent.CanceledException e) {
// ignore
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
index 4a5342e..5d5d562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
@@ -18,9 +18,10 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import com.android.systemui.statusbar.pipeline.dagger.AirplaneTableLog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -46,7 +47,7 @@
@Inject
constructor(
interactor: AirplaneModeInteractor,
- logger: ConnectivityPipelineLogger,
+ @AirplaneTableLog logger: TableLogBuffer,
@Application private val scope: CoroutineScope,
) : AirplaneModeViewModel {
override val isAirplaneModeIconVisible: StateFlow<Boolean> =
@@ -56,6 +57,11 @@
isAirplaneMode && !isAirplaneIconForceHidden
}
.distinctUntilChanged()
- .logOutputChange(logger, "isAirplaneModeIconVisible")
+ .logDiffsForTable(
+ logger,
+ columnPrefix = "",
+ columnName = "isAirplaneModeIconVisible",
+ initialValue = false,
+ )
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
}
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt
similarity index 65%
copy from telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
copy to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt
index 2a498f0..d1aa79e 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.telephony.satellite.stub;
+package com.android.systemui.statusbar.pipeline.dagger
-import android.telephony.satellite.stub.SatelliteModemState;
+import javax.inject.Qualifier
-/**
- * Consumer pattern for a request that receives a SatelliteModemState from the SatelliteService.
- * @hide
- */
-oneway interface ISatelliteModemStateConsumer {
- void accept(in SatelliteModemState result);
-}
+/** Logs for inputs into the mobile pipeline. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class MobileInputLog
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt
similarity index 65%
rename from telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt
index 2a498f0..5face22 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.telephony.satellite.stub;
+package com.android.systemui.statusbar.pipeline.dagger
-import android.telephony.satellite.stub.SatelliteModemState;
+import javax.inject.Qualifier
-/**
- * Consumer pattern for a request that receives a SatelliteModemState from the SatelliteService.
- * @hide
- */
-oneway interface ISatelliteModemStateConsumer {
- void accept(in SatelliteModemState result);
-}
+/** Logs for connectivity-related inputs that are shared across wifi, mobile, etc. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class SharedConnectivityInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 60de1a3..4464751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -19,8 +19,10 @@
import android.net.wifi.WifiManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
@@ -107,6 +109,13 @@
@Provides
@SysUISingleton
+ @WifiInputLog
+ fun provideWifiInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("WifiInputLog", 50)
+ }
+
+ @Provides
+ @SysUISingleton
@WifiTableLog
fun provideWifiTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
return factory.create("WifiTableLog", 100)
@@ -121,9 +130,23 @@
@Provides
@SysUISingleton
+ @SharedConnectivityInputLog
+ fun provideSharedConnectivityTableLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("SharedConnectivityInputLog", 30)
+ }
+
+ @Provides
+ @SysUISingleton
@MobileSummaryLog
fun provideMobileSummaryLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
return factory.create("MobileSummaryLog", 100)
}
+
+ @Provides
+ @SysUISingleton
+ @MobileInputLog
+ fun provideMobileInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("MobileInputLog", 100)
+ }
}
}
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
similarity index 65%
copy from telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
copy to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
index 2a498f0..6db69447 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatelliteModemStateConsumer.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.telephony.satellite.stub;
+package com.android.systemui.statusbar.pipeline.dagger
-import android.telephony.satellite.stub.SatelliteModemState;
+import javax.inject.Qualifier
-/**
- * Consumer pattern for a request that receives a SatelliteModemState from the SatelliteService.
- * @hide
- */
-oneway interface ISatelliteModemStateConsumer {
- void accept(in SatelliteModemState result);
-}
+/** Wifi logs for inputs into the wifi pipeline. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class WifiInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index 5769f90..bb3b9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -31,7 +31,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -57,7 +57,7 @@
broadcastDispatcher: BroadcastDispatcher,
private val carrierConfigManager: CarrierConfigManager,
dumpManager: DumpManager,
- logger: ConnectivityPipelineLogger,
+ logger: MobileInputLogger,
@Application scope: CoroutineScope,
) : Dumpable {
private var isListening = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index dcce0ea..96b96f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -47,8 +47,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -85,7 +85,7 @@
broadcastDispatcher: BroadcastDispatcher,
private val mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
- logger: ConnectivityPipelineLogger,
+ logger: MobileInputLogger,
override val tableLogBuffer: TableLogBuffer,
scope: CoroutineScope,
) : MobileConnectionRepository {
@@ -291,7 +291,7 @@
private val broadcastDispatcher: BroadcastDispatcher,
private val context: Context,
private val telephonyManager: TelephonyManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
private val carrierConfigRepository: CarrierConfigRepository,
private val mobileMappingsProxy: MobileMappingsProxy,
@Background private val bgDispatcher: CoroutineDispatcher,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 73ce5e6..b3d5b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -49,9 +49,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.kotlin.pairwise
@@ -84,7 +83,7 @@
private val connectivityManager: ConnectivityManager,
private val subscriptionManager: SubscriptionManager,
private val telephonyManager: TelephonyManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
@MobileSummaryLog private val tableLogger: TableLogBuffer,
mobileMappingsProxy: MobileMappingsProxy,
broadcastDispatcher: BroadcastDispatcher,
@@ -222,13 +221,13 @@
private val carrierConfigChangedEvent =
broadcastDispatcher
.broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
- .logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
+ .onEach { logger.logActionCarrierConfigChanged() }
override val defaultDataSubRatConfig: StateFlow<Config> =
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultDataSubRatConfig")
+ .onEach { logger.logDefaultDataSubRatConfig(it) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
@@ -239,13 +238,13 @@
defaultDataSubRatConfig
.map { mobileMappingsProxy.mapIconSets(it) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultMobileIconMapping")
+ .onEach { logger.logDefaultMobileIconMapping(it) }
override val defaultMobileIconGroup: Flow<MobileIconGroup> =
defaultDataSubRatConfig
.map { mobileMappingsProxy.getDefaultIcons(it) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultMobileIconGroup")
+ .onEach { logger.logDefaultMobileIconGroup(it) }
override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository {
if (!isValidSubId(subId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 5a2e11e..142c372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -30,7 +30,6 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.util.CarrierConfigTracker
@@ -111,7 +110,6 @@
constructor(
private val mobileConnectionsRepo: MobileConnectionsRepository,
private val carrierConfigTracker: CarrierConfigTracker,
- private val logger: ConnectivityPipelineLogger,
@MobileSummaryLog private val tableLogger: TableLogBuffer,
connectivityRepository: ConnectivityRepository,
userSetupRepo: UserSetupRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
new file mode 100644
index 0000000..3cbd2b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
@@ -0,0 +1,202 @@
+/*
+ * 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.pipeline.mobile.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.TelephonyDisplayInfo
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.MobileInputLog
+import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
+import javax.inject.Inject
+
+/** Logs for inputs into the mobile pipeline. */
+@SysUISingleton
+class MobileInputLogger
+@Inject
+constructor(
+ @MobileInputLog private val buffer: LogBuffer,
+) {
+ fun logOnCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ LoggerHelper.logOnCapabilitiesChanged(
+ buffer,
+ TAG,
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback,
+ )
+ }
+
+ fun logOnLost(network: Network) {
+ LoggerHelper.logOnLost(buffer, TAG, network)
+ }
+
+ fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = serviceState.isEmergencyOnly
+ bool2 = serviceState.roaming
+ str1 = serviceState.operatorAlphaShort
+ },
+ {
+ "onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
+ " operator=$str1"
+ }
+ )
+ }
+
+ fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ str1 = signalStrength.toString()
+ },
+ { "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
+ )
+ }
+
+ fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ int2 = dataState
+ str1 = networkType.toString()
+ },
+ { "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
+ )
+ }
+
+ fun logOnDataActivity(direction: Int, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ int2 = direction
+ },
+ { "onDataActivity: subId=$int1 direction=$int2" },
+ )
+ }
+
+ fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = active
+ },
+ { "onCarrierNetworkChange: subId=$int1 active=$bool1" },
+ )
+ }
+
+ fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ str1 = displayInfo.toString()
+ },
+ { "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
+ )
+ }
+
+ fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter updated internally: $str1" },
+ )
+ }
+
+ fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
+ )
+ }
+
+ fun logCarrierConfigChanged(subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { int1 = subId },
+ { "onCarrierConfigChanged: subId=$int1" },
+ )
+ }
+
+ fun logOnDataEnabledChanged(enabled: Boolean, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = enabled
+ },
+ { "onDataEnabledChanged: subId=$int1 enabled=$bool1" },
+ )
+ }
+
+ fun logActionCarrierConfigChanged() {
+ buffer.log(TAG, LogLevel.INFO, {}, { "Intent received: ACTION_CARRIER_CONFIG_CHANGED" })
+ }
+
+ fun logDefaultDataSubRatConfig(config: MobileMappings.Config) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = config.toString() },
+ { "defaultDataSubRatConfig: $str1" }
+ )
+ }
+
+ fun logDefaultMobileIconMapping(mapping: Map<String, SignalIcon.MobileIconGroup>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = mapping.toString() },
+ { "defaultMobileIconMapping: $str1" }
+ )
+ }
+
+ fun logDefaultMobileIconGroup(group: SignalIcon.MobileIconGroup) {
+ buffer.log(TAG, LogLevel.INFO, { str1 = group.name }, { "defaultMobileIconGroup: $str1" })
+ }
+}
+
+private const val TAG = "MobileInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index ef75713..da63ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -22,8 +22,8 @@
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -55,7 +55,7 @@
interactor: MobileIconsInteractor,
private val iconController: StatusBarIconController,
private val iconsViewModelFactory: MobileIconsViewModel.Factory,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
) : CoreStartable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 185b668..8cb52af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
@@ -42,7 +41,6 @@
val subscriptionIdsFlow: StateFlow<List<Int>>,
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
- private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
@@ -83,7 +81,6 @@
constructor(
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
- private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
@@ -93,7 +90,6 @@
subscriptionIdsFlow,
interactor,
airplaneModeInteractor,
- logger,
constants,
scope,
statusBarPipelineFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
index 0c9b86c..0fe5329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
@@ -22,7 +22,6 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import java.io.PrintWriter
import javax.inject.Inject
@@ -40,7 +39,7 @@
telephonyManager: TelephonyManager,
) : Dumpable {
init {
- dumpManager.registerNormalDumpable("${SB_LOGGING_TAG}Constants", this)
+ dumpManager.registerNormalDumpable("ConnectivityConstants", this)
}
/** True if this device has the capability for data connections and false otherwise. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
new file mode 100644
index 0000000..95548b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.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.statusbar.pipeline.shared
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.SharedConnectivityInputLog
+import javax.inject.Inject
+
+/** Logs for connectivity-related inputs that are shared across wifi, mobile, etc. */
+@SysUISingleton
+class ConnectivityInputLogger
+@Inject
+constructor(
+ @SharedConnectivityInputLog private val buffer: LogBuffer,
+) {
+ fun logTuningChanged(tuningList: String?) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = tuningList }, { "onTuningChanged: $str1" })
+ }
+}
+
+private const val TAG = "ConnectivityInputLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
deleted file mode 100644
index 45036969..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ /dev/null
@@ -1,285 +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.pipeline.shared
-
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.telephony.ServiceState
-import android.telephony.SignalStrength
-import android.telephony.TelephonyDisplayInfo
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.dagger.StatusBarConnectivityLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.onEach
-
-@SysUISingleton
-class ConnectivityPipelineLogger
-@Inject
-constructor(
- @StatusBarConnectivityLog private val buffer: LogBuffer,
-) {
- /**
- * Logs a change in one of the **raw inputs** to the connectivity pipeline.
- *
- * Use this method for inputs that don't have any extra information besides their callback name.
- */
- fun logInputChange(callbackName: String) {
- buffer.log(SB_LOGGING_TAG, LogLevel.INFO, { str1 = callbackName }, { "Input: $str1" })
- }
-
- /** Logs a change in one of the **raw inputs** to the connectivity pipeline. */
- fun logInputChange(callbackName: String, changeInfo: String?) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = callbackName
- str2 = changeInfo
- },
- { "Input: $str1: $str2" }
- )
- }
-
- /** Logs a **data transformation** that we performed within the connectivity pipeline. */
- fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
- if (oldValue == newValue) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = transformationName
- str2 = oldValue.toString()
- },
- { "Transform: $str1: $str2 (transformation didn't change it)" }
- )
- } else {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = transformationName
- str2 = oldValue.toString()
- str3 = newValue.toString()
- },
- { "Transform: $str1: $str2 -> $str3" }
- )
- }
- }
-
- /** Logs a change in one of the **outputs** to the connectivity pipeline. */
- fun logOutputChange(outputParamName: String, changeInfo: String) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = outputParamName
- str2 = changeInfo
- },
- { "Output: $str1: $str2" }
- )
- }
-
- fun logOnCapabilitiesChanged(
- network: Network,
- networkCapabilities: NetworkCapabilities,
- isDefaultNetworkCallback: Boolean,
- ) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- bool1 = isDefaultNetworkCallback
- int1 = network.getNetId()
- str1 = networkCapabilities.toString()
- },
- { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
- )
- }
-
- fun logOnLost(network: Network) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { int1 = network.getNetId() },
- { "onLost: net=$int1" }
- )
- }
-
- fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = serviceState.isEmergencyOnly
- bool2 = serviceState.roaming
- str1 = serviceState.operatorAlphaShort
- },
- {
- "onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
- " operator=$str1"
- }
- )
- }
-
- fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- str1 = signalStrength.toString()
- },
- { "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
- )
- }
-
- fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- int2 = dataState
- str1 = networkType.toString()
- },
- { "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
- )
- }
-
- fun logOnDataActivity(direction: Int, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- int2 = direction
- },
- { "onDataActivity: subId=$int1 direction=$int2" },
- )
- }
-
- fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = active
- },
- { "onCarrierNetworkChange: subId=$int1 active=$bool1" },
- )
- }
-
- fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- str1 = displayInfo.toString()
- },
- { "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
- )
- }
-
- // TODO(b/238425913): We should split this class into mobile-specific and wifi-specific loggers.
-
- fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter updated internally: $str1" },
- )
- }
-
- fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
- )
- }
-
- fun logCarrierConfigChanged(subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { int1 = subId },
- { "onCarrierConfigChanged: subId=$int1" },
- )
- }
-
- fun logOnDataEnabledChanged(enabled: Boolean, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = enabled
- },
- { "onDataEnabledChanged: subId=$int1 enabled=$bool1" },
- )
- }
-
- companion object {
- const val SB_LOGGING_TAG = "SbConnectivity"
-
- /** Log a change in one of the **inputs** to the connectivity pipeline. */
- fun Flow<Unit>.logInputChange(
- logger: ConnectivityPipelineLogger,
- inputParamName: String,
- ): Flow<Unit> {
- return this.onEach { logger.logInputChange(inputParamName) }
- }
-
- /**
- * Log a change in one of the **inputs** to the connectivity pipeline.
- *
- * @param prettyPrint an optional function to transform the value into a readable string.
- * [toString] is used if no custom function is provided.
- */
- fun <T> Flow<T>.logInputChange(
- logger: ConnectivityPipelineLogger,
- inputParamName: String,
- prettyPrint: (T) -> String = { it.toString() }
- ): Flow<T> {
- return this.onEach { logger.logInputChange(inputParamName, prettyPrint(it)) }
- }
-
- /**
- * Log a change in one of the **outputs** to the connectivity pipeline.
- *
- * @param prettyPrint an optional function to transform the value into a readable string.
- * [toString] is used if no custom function is provided.
- */
- fun <T> Flow<T>.logOutputChange(
- logger: ConnectivityPipelineLogger,
- outputParamName: String,
- prettyPrint: (T) -> String = { it.toString() }
- ): Flow<T> {
- return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
new file mode 100644
index 0000000..6f29e33
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.pipeline.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+
+/** Helper object for logs that are shared between wifi and mobile. */
+object LoggerHelper {
+ fun logOnCapabilitiesChanged(
+ buffer: LogBuffer,
+ tag: String,
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ buffer.log(
+ tag,
+ LogLevel.INFO,
+ {
+ bool1 = isDefaultNetworkCallback
+ int1 = network.getNetId()
+ str1 = networkCapabilities.toString()
+ },
+ { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
+ )
+ }
+
+ fun logOnLost(buffer: LogBuffer, tag: String, network: Network) {
+ buffer.log(tag, LogLevel.INFO, { int1 = network.getNetId() }, { "onLost: net=$int1" })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
index 45c6d46..5d9ba018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -26,8 +26,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.StatusBarIconController
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.tuner.TunerService
@@ -45,59 +44,61 @@
* types of connectivity (wifi, mobile, ethernet, etc.)
*/
interface ConnectivityRepository {
- /**
- * Observable for the current set of connectivity icons that should be force-hidden.
- */
+ /** Observable for the current set of connectivity icons that should be force-hidden. */
val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>>
}
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
-class ConnectivityRepositoryImpl @Inject constructor(
+class ConnectivityRepositoryImpl
+@Inject
+constructor(
private val connectivitySlots: ConnectivitySlots,
context: Context,
dumpManager: DumpManager,
- logger: ConnectivityPipelineLogger,
+ logger: ConnectivityInputLogger,
@Application scope: CoroutineScope,
tunerService: TunerService,
) : ConnectivityRepository, Dumpable {
init {
- dumpManager.registerDumpable("${SB_LOGGING_TAG}Repository", this)
+ dumpManager.registerDumpable("ConnectivityRepository", this)
}
// The default set of hidden icons to use if we don't get any from [TunerService].
private val defaultHiddenIcons: Set<ConnectivitySlot> =
- context.resources.getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
- .asList()
- .toSlotSet(connectivitySlots)
+ context.resources
+ .getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
+ .asList()
+ .toSlotSet(connectivitySlots)
- override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = conflatedCallbackFlow {
- val callback = object : TunerService.Tunable {
- override fun onTuningChanged(key: String, newHideList: String?) {
- if (key != HIDDEN_ICONS_TUNABLE_KEY) {
- return
- }
- logger.logInputChange("onTuningChanged", newHideList)
+ override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> =
+ conflatedCallbackFlow {
+ val callback =
+ object : TunerService.Tunable {
+ override fun onTuningChanged(key: String, newHideList: String?) {
+ if (key != HIDDEN_ICONS_TUNABLE_KEY) {
+ return
+ }
+ logger.logTuningChanged(newHideList)
- val outputList = newHideList?.split(",")?.toSlotSet(connectivitySlots)
- ?: defaultHiddenIcons
- trySend(outputList)
+ val outputList =
+ newHideList?.split(",")?.toSlotSet(connectivitySlots)
+ ?: defaultHiddenIcons
+ trySend(outputList)
+ }
+ }
+ tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
+
+ awaitClose { tunerService.removeTunable(callback) }
}
- }
- tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
-
- awaitClose { tunerService.removeTunable(callback) }
- }
- .stateIn(
- scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = defaultHiddenIcons
- )
+ .stateIn(
+ scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = defaultHiddenIcons
+ )
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("defaultHiddenIcons=$defaultHiddenIcons")
- }
+ pw.apply { println("defaultHiddenIcons=$defaultHiddenIcons") }
}
companion object {
@@ -111,8 +112,7 @@
private fun List<String>.toSlotSet(
connectivitySlots: ConnectivitySlots
): Set<ConnectivitySlot> {
- return this
- .filter { it.isNotBlank() }
+ return this.filter { it.isNotBlank() }
.mapNotNull { connectivitySlots.getSlotFromName(it) }
.toSet()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 7b486c1..ee58160 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -39,12 +39,11 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -58,6 +57,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/** Real implementation of [WifiRepository]. */
@@ -70,7 +70,7 @@
constructor(
broadcastDispatcher: BroadcastDispatcher,
connectivityManager: ConnectivityManager,
- logger: ConnectivityPipelineLogger,
+ logger: WifiInputLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
@Main mainExecutor: Executor,
@Application scope: CoroutineScope,
@@ -80,7 +80,7 @@
private val wifiStateChangeEvents: Flow<Unit> =
broadcastDispatcher
.broadcastFlow(IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION))
- .logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
+ .onEach { logger.logIntent("WIFI_STATE_CHANGED_ACTION") }
private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
MutableSharedFlow(extraBufferCapacity = 1)
@@ -173,11 +173,6 @@
networkCapabilities,
wifiManager,
)
- logger.logTransformation(
- WIFI_NETWORK_CALLBACK_NAME,
- oldValue = currentWifi,
- newValue = wifiNetworkModel,
- )
currentWifi = wifiNetworkModel
trySend(wifiNetworkModel)
}
@@ -194,11 +189,6 @@
wifi.networkId == network.getNetId()
) {
val newNetworkModel = WifiNetworkModel.Inactive
- logger.logTransformation(
- WIFI_NETWORK_CALLBACK_NAME,
- oldValue = wifi,
- newValue = newNetworkModel,
- )
currentWifi = newNetworkModel
trySend(newNetworkModel)
}
@@ -228,7 +218,7 @@
override val wifiActivity: StateFlow<DataActivityModel> =
conflatedCallbackFlow {
val callback = TrafficStateCallback { state ->
- logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
+ logger.logActivity(prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
@@ -336,8 +326,6 @@
.addTransportType(TRANSPORT_CELLULAR)
.build()
- private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
-
private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
"Wifi network was carrier merged but had invalid sub ID"
}
@@ -348,7 +336,7 @@
constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val connectivityManager: ConnectivityManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: WifiInputLogger,
@WifiTableLog private val wifiTableLogBuffer: TableLogBuffer,
@Main private val mainExecutor: Executor,
@Application private val scope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
index 4f7fe28..8bea772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
@@ -21,7 +21,6 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import java.io.PrintWriter
import javax.inject.Inject
@@ -30,12 +29,14 @@
* logging purposes.
*/
@SysUISingleton
-class WifiConstants @Inject constructor(
- context: Context,
- dumpManager: DumpManager,
+class WifiConstants
+@Inject
+constructor(
+ context: Context,
+ dumpManager: DumpManager,
) : Dumpable {
init {
- dumpManager.registerDumpable("${SB_LOGGING_TAG}WifiConstants", this)
+ dumpManager.registerNormalDumpable("WifiConstants", this)
}
/** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
@@ -43,8 +44,6 @@
context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
- }
+ pw.apply { println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled") }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
new file mode 100644
index 0000000..a32e475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.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.pipeline.wifi.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
+import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
+import javax.inject.Inject
+
+/**
+ * Logger for all the wifi-related inputs (intents, callbacks, etc.) that the wifi repo receives.
+ */
+@SysUISingleton
+class WifiInputLogger
+@Inject
+constructor(
+ @WifiInputLog val buffer: LogBuffer,
+) {
+ fun logOnCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ LoggerHelper.logOnCapabilitiesChanged(
+ buffer,
+ TAG,
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback,
+ )
+ }
+
+ fun logOnLost(network: Network) {
+ LoggerHelper.logOnLost(buffer, TAG, network)
+ }
+
+ fun logIntent(intentName: String) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = intentName }, { "Intent received: $str1" })
+ }
+
+ fun logActivity(activity: String) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "Activity: $str1" })
+ }
+}
+
+private const val TAG = "WifiInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 0f5ff91..1057231 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -34,8 +34,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
@@ -69,7 +67,6 @@
airplaneModeViewModel: AirplaneModeViewModel,
connectivityConstants: ConnectivityConstants,
private val context: Context,
- logger: ConnectivityPipelineLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
interactor: WifiInteractor,
@Application private val scope: CoroutineScope,
@@ -143,29 +140,35 @@
)
/** The wifi activity status. Null if we shouldn't display the activity status. */
- private val activity: Flow<DataActivityModel?> =
+ private val activity: Flow<DataActivityModel> = run {
+ val default = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
if (!connectivityConstants.shouldShowActivityConfig) {
- flowOf(null)
+ flowOf(default)
} else {
combine(interactor.activity, interactor.ssid) { activity, ssid ->
when (ssid) {
- null -> null
+ null -> default
else -> activity
}
}
}
.distinctUntilChanged()
- .logOutputChange(logger, "activity")
- .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
+ .logDiffsForTable(
+ wifiTableLogBuffer,
+ columnPrefix = "VM.activity",
+ initialValue = default,
+ )
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = default)
+ }
private val isActivityInViewVisible: Flow<Boolean> =
activity
- .map { it?.hasActivityIn == true }
+ .map { it.hasActivityIn }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
private val isActivityOutViewVisible: Flow<Boolean> =
activity
- .map { it?.hasActivityOut == true }
+ .map { it.hasActivityOut }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
private val isActivityContainerVisible: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index e4e59a0..3263c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -25,6 +25,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.ArrayMap;
import android.view.accessibility.AccessibilityManager;
@@ -91,6 +92,7 @@
mUiEventLogger = uiEventLogger;
Resources resources = context.getResources();
mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
+ mStickyDisplayTime = resources.getInteger(R.integer.sticky_heads_up_notification_time);
mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
mSnoozedPackages = new ArrayMap<>();
@@ -408,8 +410,11 @@
@Override
public boolean isSticky() {
- return (mEntry.isRowPinned() && expanded)
- || remoteInputActive || hasFullScreenIntent(mEntry);
+ final boolean isSticky = (mEntry.isRowPinned() && expanded)
+ || remoteInputActive
+ || hasFullScreenIntent(mEntry)
+ || mEntry.isStickyAndNotDemoted();
+ return isSticky;
}
@Override
@@ -465,8 +470,15 @@
return super.calculatePostTime() + mTouchAcceptanceDelay;
}
+ /**
+ * @return When the notification should auto-dismiss itself, based on
+ * {@link SystemClock#elapsedRealTime()}
+ */
@Override
protected long calculateFinishTime() {
+ if (isSticky()) {
+ return mEntry.mCreationElapsedRealTime + mStickyDisplayTime;
+ }
return mPostTime + getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 1ae1eae..8929e02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -56,7 +56,7 @@
/**
* Whether the bouncer (PIN/password entry) is currently visible.
*/
- boolean isBouncerShowing();
+ boolean isPrimaryBouncerShowing();
/**
* If swiping up will unlock without asking for a password.
@@ -196,7 +196,7 @@
/** **/
default void notifyKeyguardState(boolean showing, boolean occluded) {}
/** **/
- default void notifyBouncerShowing(boolean showing) {}
+ default void notifyPrimaryBouncerShowing(boolean showing) {}
/**
* Updates the keyguard state to reflect that it's in the process of being dismissed, either by
@@ -244,7 +244,7 @@
/**
* Called when the bouncer (PIN/password entry) is shown or hidden.
*/
- default void onBouncerShowingChanged() {}
+ default void onPrimaryBouncerShowingChanged() {}
/**
* Triggered when the device was just unlocked and the lock screen is being dismissed.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 9ad36fd5..805368c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -65,7 +65,7 @@
private boolean mCanDismissLockScreen;
private boolean mShowing;
- private boolean mBouncerShowing;
+ private boolean mPrimaryBouncerShowing;
private boolean mSecure;
private boolean mOccluded;
@@ -157,8 +157,8 @@
}
@Override
- public boolean isBouncerShowing() {
- return mBouncerShowing;
+ public boolean isPrimaryBouncerShowing() {
+ return mPrimaryBouncerShowing;
}
@Override
@@ -339,11 +339,11 @@
}
@Override
- public void notifyBouncerShowing(boolean showing) {
- if (mBouncerShowing != showing) {
- mBouncerShowing = showing;
+ public void notifyPrimaryBouncerShowing(boolean showing) {
+ if (mPrimaryBouncerShowing != showing) {
+ mPrimaryBouncerShowing = showing;
- new ArrayList<>(mCallbacks).forEach(Callback::onBouncerShowingChanged);
+ new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index c0cbd62..462504e 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -26,6 +26,9 @@
import android.util.ArrayMap
import android.util.Log
import android.view.InputDevice
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -33,7 +36,6 @@
import com.android.systemui.flags.Flags
import com.android.systemui.shared.hardware.hasInputDevice
import com.android.systemui.shared.hardware.isInternalStylusSource
-import com.android.systemui.statusbar.notification.collection.listbuilder.DEBUG
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -61,12 +63,17 @@
private val stylusCallbacks: CopyOnWriteArrayList<StylusCallback> = CopyOnWriteArrayList()
private val stylusBatteryCallbacks: CopyOnWriteArrayList<StylusBatteryCallback> =
CopyOnWriteArrayList()
+
// This map should only be accessed on the handler
private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap()
+ private val inputDeviceBtSessionIdMap: MutableMap<Int, InstanceId> = ArrayMap()
// These variables should only be accessed on the handler
private var hasStarted: Boolean = false
private var isInUsiSession: Boolean = false
+ private var usiSessionId: InstanceId? = null
+
+ @VisibleForTesting var instanceIdSequence = InstanceIdSequence(1 shl 13)
/**
* Starts listening to InputManager InputDevice events. Will also load the InputManager snapshot
@@ -120,7 +127,7 @@
if (btAddress != null) {
onStylusUsed()
- onStylusBluetoothConnected(btAddress)
+ onStylusBluetoothConnected(deviceId, btAddress)
executeStylusCallbacks { cb -> cb.onStylusBluetoothConnected(deviceId, btAddress) }
}
}
@@ -136,12 +143,12 @@
inputDeviceAddressMap[deviceId] = currAddress
if (prevAddress == null && currAddress != null) {
- onStylusBluetoothConnected(currAddress)
+ onStylusBluetoothConnected(deviceId, currAddress)
executeStylusCallbacks { cb -> cb.onStylusBluetoothConnected(deviceId, currAddress) }
}
if (prevAddress != null && currAddress == null) {
- onStylusBluetoothDisconnected(prevAddress)
+ onStylusBluetoothDisconnected(deviceId, prevAddress)
executeStylusCallbacks { cb -> cb.onStylusBluetoothDisconnected(deviceId, prevAddress) }
}
}
@@ -155,7 +162,7 @@
val btAddress: String? = inputDeviceAddressMap[deviceId]
inputDeviceAddressMap.remove(deviceId)
if (btAddress != null) {
- onStylusBluetoothDisconnected(btAddress)
+ onStylusBluetoothDisconnected(deviceId, btAddress)
executeStylusCallbacks { cb -> cb.onStylusBluetoothDisconnected(deviceId, btAddress) }
}
executeStylusCallbacks { cb -> cb.onStylusRemoved(deviceId) }
@@ -208,8 +215,8 @@
}
}
- private fun onStylusBluetoothConnected(btAddress: String) {
- uiEventLogger.log(StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED)
+ private fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {
+ trackAndLogBluetoothSession(deviceId, true)
val device: BluetoothDevice = bluetoothAdapter?.getRemoteDevice(btAddress) ?: return
try {
bluetoothAdapter.addOnMetadataChangedListener(device, executor, this)
@@ -218,8 +225,8 @@
}
}
- private fun onStylusBluetoothDisconnected(btAddress: String) {
- uiEventLogger.log(StylusUiEvent.BLUETOOTH_STYLUS_DISCONNECTED)
+ private fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) {
+ trackAndLogBluetoothSession(deviceId, false)
val device: BluetoothDevice = bluetoothAdapter?.getRemoteDevice(btAddress) ?: return
try {
bluetoothAdapter.removeOnMetadataChangedListener(device, this)
@@ -251,21 +258,51 @@
private fun trackAndLogUsiSession(deviceId: Int, batteryStateValid: Boolean) {
// TODO(b/268618918) handle cases where an invalid battery callback from a previous stylus
// is sent after the actual valid callback
- if (batteryStateValid && !isInUsiSession) {
+ if (batteryStateValid && usiSessionId == null) {
if (DEBUG) {
Log.d(
TAG,
"USI battery newly present, entering new USI session. Device ID: $deviceId"
)
}
- isInUsiSession = true
- uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
- } else if (!batteryStateValid && isInUsiSession) {
+ usiSessionId = instanceIdSequence.newInstanceId()
+ uiEventLogger.logWithInstanceId(
+ StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED,
+ 0,
+ null,
+ usiSessionId
+ )
+ } else if (!batteryStateValid && usiSessionId != null) {
if (DEBUG) {
Log.d(TAG, "USI battery newly absent, exiting USI session Device ID: $deviceId")
}
- isInUsiSession = false
- uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+ uiEventLogger.logWithInstanceId(
+ StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED,
+ 0,
+ null,
+ usiSessionId
+ )
+ usiSessionId = null
+ }
+ }
+
+ private fun trackAndLogBluetoothSession(deviceId: Int, bluetoothConnected: Boolean) {
+ if (bluetoothConnected) {
+ inputDeviceBtSessionIdMap[deviceId] = instanceIdSequence.newInstanceId()
+ uiEventLogger.logWithInstanceId(
+ StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED,
+ 0,
+ null,
+ inputDeviceBtSessionIdMap[deviceId]
+ )
+ } else {
+ uiEventLogger.logWithInstanceId(
+ StylusUiEvent.BLUETOOTH_STYLUS_DISCONNECTED,
+ 0,
+ null,
+ inputDeviceBtSessionIdMap[deviceId]
+ )
+ inputDeviceBtSessionIdMap.remove(deviceId)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
index 89453ad..ec0a6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
@@ -33,6 +33,8 @@
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
@@ -62,6 +64,9 @@
private var batteryCapacity = 1.0f
private var suppressed = false
private var inputDeviceId: Int? = null
+ private var instanceId: InstanceId? = null
+
+ @VisibleForTesting var instanceIdSequence = InstanceIdSequence(1 shl 13)
fun init() {
val filter =
@@ -126,6 +131,7 @@
}
private fun hideNotification() {
+ instanceId = null
notificationManager.cancel(USI_NOTIFICATION_ID)
}
@@ -204,15 +210,28 @@
}
}
+ /**
+ * Logs a stylus USI battery event with instance ID and battery level. The instance ID
+ * represents the notification instance, and is reset when a notification is cancelled.
+ */
private fun logUiEvent(metricId: StylusUiEvent) {
- uiEventLogger.logWithPosition(
+ uiEventLogger.logWithInstanceIdAndPosition(
metricId,
ActivityManager.getCurrentUser(),
context.packageName,
+ getInstanceId(),
(batteryCapacity * 100.0).toInt()
)
}
+ @VisibleForTesting
+ fun getInstanceId(): InstanceId? {
+ if (instanceId == null) {
+ instanceId = instanceId ?: instanceIdSequence.newInstanceId()
+ }
+ return instanceId
+ }
+
companion object {
// Low battery threshold matches CrOS, see:
// https://source.chromium.org/chromium/chromium/src/+/main:ash/system/power/peripheral_battery_notifier.cc;l=41
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index c1f0c58..39dda8c 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -55,15 +55,15 @@
Pair.create("error_container", MDC.errorContainer),
Pair.create("on_error_container", MDC.onErrorContainer),
Pair.create("primary_fixed", MDC.primaryFixed),
- Pair.create("primary_fixed_darker", MDC.primaryFixedDarker),
+ Pair.create("primary_fixed_dim", MDC.primaryFixedDim),
Pair.create("on_primary_fixed", MDC.onPrimaryFixed),
Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant),
Pair.create("secondary_fixed", MDC.secondaryFixed),
- Pair.create("secondary_fixed_darker", MDC.secondaryFixedDarker),
+ Pair.create("secondary_fixed_dim", MDC.secondaryFixedDim),
Pair.create("on_secondary_fixed", MDC.onSecondaryFixed),
Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant),
Pair.create("tertiary_fixed", MDC.tertiaryFixed),
- Pair.create("tertiary_fixed_darker", MDC.tertiaryFixedDarker),
+ Pair.create("tertiary_fixed_dim", MDC.tertiaryFixedDim),
Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed),
Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant),
Pair.create("control_activated", MDC.controlActivated),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index badeb27..81fef7a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -31,6 +31,7 @@
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -338,6 +339,70 @@
}
@Test
+ fun isWakeupForceDismissKeyguard_singleValue() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift is considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ PowerManager.WAKE_REASON_LIFT.toString(), currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN only WAKE_REASON_LIFT is considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ if (wakeReason == PowerManager.WAKE_REASON_LIFT) {
+ assertTrue(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ } else {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+ }
+
+ @Test
+ fun isWakeupForceDismissKeyguard_emptyValues() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift and tap are considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ " ", currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN no wake up gestures are considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+
+ @Test
+ fun isWakeupForceDismissKeyguard_multiValue() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift and tap are considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ PowerManager.WAKE_REASON_LIFT.toString() +
+ "|" +
+ PowerManager.WAKE_REASON_TAP.toString(),
+ currentUser
+ )
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN WAKE_REASON_LIFT and WAKE_REASON TAP are considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ if (wakeReason == PowerManager.WAKE_REASON_LIFT ||
+ wakeReason == PowerManager.WAKE_REASON_TAP) {
+ assertTrue(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ } else {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+ }
+
+ @Test
fun dump_onUnlockIntentWhenBiometricEnrolled_invalidNum_noArrayOutOfBoundsException() {
// GIVEN an invalid input (-1)
secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index f7fec80..480b8f9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -85,6 +86,7 @@
@Mock private lateinit var transitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var repository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
@Mock private lateinit var smallLogBuffer: LogBuffer
@Mock private lateinit var largeLogBuffer: LogBuffer
private lateinit var underTest: ClockEventController
@@ -103,11 +105,15 @@
whenever(largeClockEvents.tickRate).thenReturn(ClockTickRate.PER_MINUTE)
repository = FakeKeyguardRepository()
+ bouncerRepository = FakeKeyguardBouncerRepository()
underTest = ClockEventController(
- KeyguardInteractor(repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags),
+ KeyguardInteractor(
+ repository = repository,
+ commandQueue = commandQueue,
+ featureFlags = featureFlags,
+ bouncerRepository = bouncerRepository,
+ ),
KeyguardTransitionInteractor(repository = transitionRepository),
broadcastDispatcher,
batteryController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index ccc4e4a..a5f90f8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -241,7 +241,7 @@
mController.init();
verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
- listenerArgumentCaptor.getValue().onClockChanged();
+ listenerArgumentCaptor.getValue().onCurrentClockChanged();
verify(mView, times(2)).setClock(mClockController, StatusBarState.SHADE);
verify(mClockEventController, times(2)).setClock(mClockController);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
deleted file mode 100644
index 4021652..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
+++ /dev/null
@@ -1,186 +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.keyguard;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.media.AudioManager;
-import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class KeyguardHostViewControllerTest extends SysuiTestCase {
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-
- private KeyguardHostView mKeyguardHostView;
- @Mock
- private AudioManager mAudioManager;
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private ViewMediatorCallback mViewMediatorCallback;
- @Mock
- KeyguardSecurityContainerController.Factory mKeyguardSecurityContainerControllerFactory;
- @Mock
- private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
-
- @Rule
- public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- private TestableResources mTestableResources;
- private KeyguardHostViewController mKeyguardHostViewController;
-
- @Before
- public void setup() {
- mTestableResources = mContext.getOrCreateTestableResources();
-
- mKeyguardHostView = new KeyguardHostView(mContext);
-
- // Explicitly disable one handed keyguard.
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, false);
-
- when(mKeyguardSecurityContainerControllerFactory.create(any(
- KeyguardSecurityContainer.SecurityCallback.class)))
- .thenReturn(mKeyguardSecurityContainerController);
- mKeyguardHostViewController = new KeyguardHostViewController(
- mKeyguardHostView, mKeyguardUpdateMonitor, mAudioManager, mTelephonyManager,
- mViewMediatorCallback, mKeyguardSecurityContainerControllerFactory);
- }
-
- @Test
- public void testHasDismissActions() {
- assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
- mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
- null /* cancelAction */);
- assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
- }
-
- @Test
- public void testOnStartingToHide() {
- mKeyguardHostViewController.onStartingToHide();
- verify(mKeyguardSecurityContainerController).onStartingToHide();
- }
-
- @Test
- public void onBouncerVisible_propagatesToKeyguardSecurityContainerController() {
- mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.VISIBLE);
- mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.INVISIBLE);
-
- InOrder order = inOrder(mKeyguardSecurityContainerController);
- order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(View.VISIBLE);
- order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(
- View.INVISIBLE);
- }
-
- @Test
- public void testGravityReappliedOnConfigurationChange() {
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
- mKeyguardHostView.setLayoutParams(lp);
-
- // Set initial gravity
- mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
- Gravity.CENTER);
-
- // Kick off the initial pass...
- mKeyguardHostViewController.init();
- assertEquals(
- ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
- Gravity.CENTER);
-
- // Now simulate a config change
- mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
-
- mKeyguardHostViewController.updateResources();
- assertEquals(
- ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
- }
-
- @Test
- public void testGravityUsesOneHandGravityWhenApplicable() {
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
- mKeyguardHostView.setLayoutParams(lp);
-
- mTestableResources.addOverride(
- R.integer.keyguard_host_view_gravity,
- Gravity.CENTER);
- mTestableResources.addOverride(
- R.integer.keyguard_host_view_one_handed_gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
-
- // Start disabled.
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, false);
-
- mKeyguardHostViewController.init();
- assertEquals(
- ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
- Gravity.CENTER);
-
- // And enable
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, true);
-
- mKeyguardHostViewController.updateResources();
- assertEquals(
- ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
- }
-
- @Test
- public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
- mKeyguardHostViewController.updateKeyguardPosition(1.0f);
-
- verify(mKeyguardSecurityContainerController).updateKeyguardPosition(1.0f);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index e1982ad..568e8d2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -23,12 +23,17 @@
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -40,12 +45,17 @@
import android.content.res.Resources;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.biometrics.BiometricSourceType;
+import android.media.AudioManager;
+import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsetsController;
+import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -61,6 +71,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.SessionTracker;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -72,6 +83,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
@@ -109,8 +121,6 @@
@Mock
private KeyguardInputViewController mInputViewController;
@Mock
- private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
- @Mock
private WindowInsetsController mWindowInsetsController;
@Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@@ -127,8 +137,6 @@
@Mock
private EmergencyButtonController mEmergencyButtonController;
@Mock
- private Resources mResources;
- @Mock
private FalsingCollector mFalsingCollector;
@Mock
private FalsingManager mFalsingManager;
@@ -148,6 +156,12 @@
private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock;
@Mock
private FalsingA11yDelegate mFalsingA11yDelegate;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private ViewMediatorCallback mViewMediatorCallback;
+ @Mock
+ private AudioManager mAudioManager;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@@ -159,18 +173,25 @@
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
private KeyguardPasswordViewController mKeyguardPasswordViewController;
private KeyguardPasswordView mKeyguardPasswordView;
+ private TestableResources mTestableResources;
@Before
public void setup() {
mConfiguration = new Configuration();
mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED.
+ mTestableResources = mContext.getOrCreateTestableResources();
- when(mResources.getConfiguration()).thenReturn(mConfiguration);
when(mView.getContext()).thenReturn(mContext);
- when(mView.getResources()).thenReturn(mResources);
+ when(mView.getResources()).thenReturn(mContext.getResources());
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* width= */ 0, /* height= */
+ 0);
+ lp.gravity = 0;
+ when(mView.getLayoutParams()).thenReturn(lp);
when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
.thenReturn(mAdminSecondaryLockScreenController);
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+ when(mKeyguardSecurityViewFlipperController.getSecurityView(any(SecurityMode.class),
+ any(KeyguardSecurityCallback.class))).thenReturn(mInputViewController);
mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
R.layout.keyguard_password_view, null));
when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
@@ -179,20 +200,21 @@
when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
.thenReturn(mKeyguardMessageAreaController);
when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN);
mKeyguardPasswordViewController = new KeyguardPasswordViewController(
(KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor,
SecurityMode.Password, mLockPatternUtils, null,
mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController,
null, mock(Resources.class), null, mKeyguardViewController);
- mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory(
+ mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
- mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create(
- mSecurityCallback);
+ mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
+ mTelephonyManager, mViewMediatorCallback, mAudioManager);
}
@Test
@@ -244,7 +266,8 @@
eq(mFalsingA11yDelegate));
// Update rotation. Should trigger update
- mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mTestableResources.getResources().getConfiguration().orientation =
+ Configuration.ORIENTATION_LANDSCAPE;
mKeyguardSecurityContainerController.updateResources();
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
@@ -278,7 +301,7 @@
@Test
public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() {
- when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(false);
+ mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, false);
when(mKeyguardSecurityViewFlipperController.getSecurityView(
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
@@ -292,7 +315,7 @@
@Test
public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() {
- when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true);
+ mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
when(mKeyguardSecurityViewFlipperController.getSecurityView(
eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
@@ -306,7 +329,7 @@
@Test
public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
- when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true);
+ mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
setupGetSecurityView();
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
@@ -488,7 +511,9 @@
SecurityMode.SimPin);
// THEN the next security method of PIN is set, and the keyguard is not marked as done
- verify(mSecurityCallback, never()).finish(anyBoolean(), anyInt());
+
+ verify(mViewMediatorCallback, never()).keyguardDonePending(anyBoolean(), anyInt());
+ verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
.isEqualTo(SecurityMode.PIN);
}
@@ -562,17 +587,19 @@
}
@Test
- public void onDensityorFontScaleChanged() {
+ public void onDensityOrFontScaleChanged() {
ArgumentCaptor<ConfigurationController.ConfigurationListener>
configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+ clearInvocations(mKeyguardSecurityViewFlipperController);
+
configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged();
verify(mView).onDensityOrFontScaleChanged();
verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
+ verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class));
}
@@ -583,11 +610,13 @@
ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+ clearInvocations(mKeyguardSecurityViewFlipperController);
+
configurationListenerArgumentCaptor.getValue().onThemeChanged();
verify(mView).reloadColors();
verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
+ verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class));
verify(mView).reset();
verify(mKeyguardSecurityViewFlipperController).reset();
@@ -600,15 +629,91 @@
ConfigurationController.ConfigurationListener.class);
mKeyguardSecurityContainerController.onViewAttached();
verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+ clearInvocations(mKeyguardSecurityViewFlipperController);
+
configurationListenerArgumentCaptor.getValue().onUiModeChanged();
verify(mView).reloadColors();
verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
+ verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN),
any(KeyguardSecurityCallback.class));
}
@Test
+ public void testHasDismissActions() {
+ assertFalse("Action not set yet", mKeyguardSecurityContainerController.hasDismissActions());
+ mKeyguardSecurityContainerController.setOnDismissAction(mock(
+ ActivityStarter.OnDismissAction.class),
+ null /* cancelAction */);
+ assertTrue("Action should exist", mKeyguardSecurityContainerController.hasDismissActions());
+ }
+
+ @Test
+ public void testOnStartingToHide() {
+ mKeyguardSecurityContainerController.onStartingToHide();
+ verify(mInputViewController).onStartingToHide();
+ }
+
+ @Test
+ public void testGravityReappliedOnConfigurationChange() {
+ // Set initial gravity
+ mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
+ Gravity.CENTER);
+
+ // Kick off the initial pass...
+ mKeyguardSecurityContainerController.onInit();
+ verify(mView).setLayoutParams(argThat(
+ (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
+ argument.gravity == Gravity.CENTER));
+ clearInvocations(mView);
+
+ // Now simulate a config change
+ mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
+ Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+
+ mKeyguardSecurityContainerController.updateResources();
+ verify(mView).setLayoutParams(argThat(
+ (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
+ argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
+ }
+
+ @Test
+ public void testGravityUsesOneHandGravityWhenApplicable() {
+ mTestableResources.addOverride(
+ R.integer.keyguard_host_view_gravity,
+ Gravity.CENTER);
+ mTestableResources.addOverride(
+ R.integer.keyguard_host_view_one_handed_gravity,
+ Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+
+ // Start disabled.
+ mTestableResources.addOverride(
+ R.bool.can_use_one_handed_bouncer, false);
+
+ mKeyguardSecurityContainerController.onInit();
+ verify(mView).setLayoutParams(argThat(
+ (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
+ argument.gravity == Gravity.CENTER));
+ clearInvocations(mView);
+
+ // And enable
+ mTestableResources.addOverride(
+ R.bool.can_use_one_handed_bouncer, true);
+
+ mKeyguardSecurityContainerController.updateResources();
+ verify(mView).setLayoutParams(argThat(
+ (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
+ argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
+ }
+
+ @Test
+ public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
+ mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f);
+ verify(mView).updatePositionByTouchX(1.0f);
+ }
+
+
+ @Test
public void testReinflateViewFlipper() {
mKeyguardSecurityContainerController.reinflateViewFlipper();
verify(mKeyguardSecurityViewFlipperController).clearViews();
@@ -641,7 +746,7 @@
}
private void setSideFpsHintEnabledFromResources(boolean enabled) {
- when(mResources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)).thenReturn(
+ mTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer,
enabled);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 841ec4b..9fe7506 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -909,6 +909,25 @@
}
@Test
+ public void noFpListeningWhenKeyguardIsOccluded_unlessAlternateBouncerShowing() {
+ // GIVEN device is awake but occluded
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mKeyguardUpdateMonitor.setKeyguardShowing(false, true);
+
+ // THEN fingerprint shouldn't listen
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
+ verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyInt(), anyInt());
+
+ // WHEN alternate bouncer is shown
+ mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
+
+ // THEN make sure FP listening begins
+ verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+ anyInt());
+ }
+
+ @Test
public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
@@ -2006,7 +2025,6 @@
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
-
@Test
public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_deviceInteractive() {
// GIVEN device is interactive
@@ -2432,6 +2450,56 @@
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
}
+ @Test
+ public void unfoldWakeup_requestActiveUnlock_forceDismissKeyguard()
+ throws RemoteException {
+ // GIVEN shouldTriggerActiveUnlock
+ keyguardIsVisible();
+ when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+ // GIVEN active unlock triggers on wakeup
+ when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+ .thenReturn(true);
+
+ // GIVEN an unfold should force dismiss the keyguard
+ when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+ PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(true);
+
+ // WHEN device wakes up from an unfold
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNFOLD_DEVICE);
+ mTestableLooper.processAllMessages();
+
+ // THEN request unlock with a keyguard dismissal
+ verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+ eq(true));
+ }
+
+ @Test
+ public void unfoldWakeup_requestActiveUnlock_noDismissKeyguard()
+ throws RemoteException {
+ // GIVEN shouldTriggerActiveUnlock on wake from UNFOLD_DEVICE
+ keyguardIsVisible();
+ when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+ // GIVEN active unlock triggers on wakeup
+ when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+ .thenReturn(true);
+
+ // GIVEN an unfold should NOT force dismiss the keyguard
+ when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+ PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(false);
+
+ // WHEN device wakes up from an unfold
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNFOLD_DEVICE);
+ mTestableLooper.processAllMessages();
+
+ // THEN request unlock WITHOUT a keyguard dismissal
+ verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+ eq(false));
+ }
+
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 3d0d036..456702b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -43,6 +43,7 @@
import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -159,9 +160,12 @@
mAuthRippleController,
mResources,
new KeyguardTransitionInteractor(mTransitionRepository),
- new KeyguardInteractor(new FakeKeyguardRepository(),
+ new KeyguardInteractor(
+ new FakeKeyguardRepository(),
mCommandQueue,
- mFeatureFlags),
+ mFeatureFlags,
+ new FakeKeyguardBouncerRepository()
+ ),
mFeatureFlags
);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index 472d207..f370ad6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -286,4 +286,26 @@
// THEN the lock icon is shown
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
}
+
+ @Test
+ public void lockIconShows_afterUnlockStateChanges() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setContentDescription(LOCKED_LABEL);
+ }
}
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 0d00e8a..e1c7417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -24,6 +24,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
@@ -33,6 +34,8 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -48,6 +51,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
@@ -177,6 +181,8 @@
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
@Captor
private ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
+ @Mock
+ private Resources mResources;
private TestableContext mContextSpy;
private Execution mExecution;
@@ -905,6 +911,25 @@
);
}
+ @Test
+ public void testUpdateFingerprintLocation_defaultPointChanges_whenConfigChanges() {
+ when(mContextSpy.getResources()).thenReturn(mResources);
+
+ doReturn(500).when(mResources)
+ .getDimensionPixelSize(eq(com.android.systemui.R.dimen
+ .physical_fingerprint_sensor_center_screen_location_y));
+ mAuthController.onConfigurationChanged(null /* newConfig */);
+
+ final Point firstFpLocation = mAuthController.getFingerprintSensorLocation();
+
+ doReturn(1000).when(mResources)
+ .getDimensionPixelSize(eq(com.android.systemui.R.dimen
+ .physical_fingerprint_sensor_center_screen_location_y));
+ mAuthController.onConfigurationChanged(null /* newConfig */);
+
+ assertNotSame(firstFpLocation, mAuthController.getFingerprintSensorLocation());
+ }
+
private void showDialog(int[] sensorIds, boolean credentialAllowed) {
mAuthController.showAuthenticationDialog(createTestPromptInfo(),
mReceiver /* receiver */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
index 4439586..2283746 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
@@ -18,9 +18,13 @@
import android.app.job.JobParameters
import android.content.Context
+import android.os.PersistableBundle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper.DeletionJobService.Companion.USER
+import com.android.systemui.util.mockito.whenever
+import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -28,18 +32,15 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.concurrent.TimeUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
class DeletionJobServiceTest : SysuiTestCase() {
- @Mock
- private lateinit var context: Context
+ @Mock private lateinit var context: Context
private lateinit var service: AuxiliaryPersistenceWrapper.DeletionJobService
@@ -53,6 +54,10 @@
@Test
fun testOnStartJob() {
+ val bundle = PersistableBundle().also { it.putInt(USER, 0) }
+ val params = mock(JobParameters::class.java)
+ whenever(params.getExtras()).thenReturn(bundle)
+
// false means job is terminated
assertFalse(service.onStartJob(mock(JobParameters::class.java)))
verify(context).deleteFile(AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
@@ -67,13 +72,17 @@
@Test
fun testJobHasRightParameters() {
val userId = 10
- `when`(context.userId).thenReturn(userId)
- `when`(context.packageName).thenReturn(mContext.packageName)
+ whenever(context.userId).thenReturn(userId)
+ whenever(context.packageName).thenReturn(mContext.packageName)
- val jobInfo = AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
+ val jobInfo =
+ AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
assertEquals(
- AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId, jobInfo.id)
+ AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId,
+ jobInfo.id
+ )
assertTrue(jobInfo.isPersisted)
+ assertEquals(userId, jobInfo.getExtras().getInt(USER))
assertEquals(TimeUnit.DAYS.toMillis(7), jobInfo.minLatencyMillis)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
new file mode 100644
index 0000000..de0e511
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.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.flags
+
+import android.os.PowerManager
+import android.test.suitebuilder.annotation.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class RestartDozeListenerTest : SysuiTestCase() {
+
+ lateinit var restartDozeListener: RestartDozeListener
+
+ val settings = FakeSettings()
+ @Mock lateinit var statusBarStateController: StatusBarStateController
+ @Mock lateinit var powerManager: PowerManager
+ val clock = FakeSystemClock()
+ lateinit var listener: StatusBarStateController.StateListener
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ restartDozeListener =
+ RestartDozeListener(settings, statusBarStateController, powerManager, clock)
+
+ val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
+ restartDozeListener.init()
+ verify(statusBarStateController).addCallback(captor.capture())
+ listener = captor.value
+ }
+
+ @Test
+ fun testStoreDreamState_onDreamingStarted() {
+ listener.onDreamingChanged(true)
+ assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isTrue()
+ }
+
+ @Test
+ fun testStoreDreamState_onDreamingStopped() {
+ listener.onDreamingChanged(false)
+ assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isFalse()
+ }
+
+ @Test
+ fun testRestoreDreamState_dreamingShouldStart() {
+ settings.putBool(RestartDozeListener.RESTART_NAP_KEY, true)
+ restartDozeListener.maybeRestartSleep()
+ verify(powerManager).wakeUp(clock.uptimeMillis())
+ verify(powerManager).goToSleep(clock.uptimeMillis())
+ }
+
+ @Test
+ fun testRestoreDreamState_dreamingShouldNot() {
+ settings.putBool(RestartDozeListener.RESTART_NAP_KEY, false)
+ restartDozeListener.maybeRestartSleep()
+ verify(powerManager, never()).wakeUp(anyLong())
+ verify(powerManager, never()).goToSleep(anyLong())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
index 4ebf974..a12315b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
@@ -50,10 +50,10 @@
@Test
fun testChange_alertsListener() {
- val flag = ReleasedFlag(1, "1", "test")
+ val flag = ReleasedFlag(1, "flag_1", "test")
serverFlagReader.listenForChanges(listOf(flag), changeListener)
- deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false)
+ deviceConfig.setProperty(NAMESPACE, "flag_1", "1", false)
executor.runAllReady()
verify(changeListener).onChange(flag)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 4415033..15a454b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -172,6 +173,7 @@
repository = FakeKeyguardRepository(),
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry = mock(),
lockPatternUtils = lockPatternUtils,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt
new file mode 100644
index 0000000..7c604f7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt
@@ -0,0 +1,428 @@
+/*
+ * 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 android.app.StatusBarManager.SESSION_KEYGUARD
+import android.content.pm.UserInfo
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT
+import android.hardware.biometrics.ComponentInfoInternal
+import android.hardware.face.FaceManager
+import android.hardware.face.FaceSensorProperties
+import android.hardware.face.FaceSensorPropertiesInternal
+import android.os.CancellationSignal
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId.fakeInstanceId
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.FaceAuthUiEvent
+import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN
+import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.shared.model.AuthenticationStatus
+import com.android.systemui.keyguard.shared.model.DetectionStatus
+import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
+import com.android.systemui.log.FaceAuthenticationLogger
+import com.android.systemui.log.SessionTracker
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardFaceAuthManagerTest : SysuiTestCase() {
+ private lateinit var underTest: KeyguardFaceAuthManagerImpl
+
+ @Mock private lateinit var faceManager: FaceManager
+ @Mock private lateinit var bypassController: KeyguardBypassController
+ @Mock private lateinit var sessionTracker: SessionTracker
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var dumpManager: DumpManager
+
+ @Captor
+ private lateinit var authenticationCallback: ArgumentCaptor<FaceManager.AuthenticationCallback>
+ @Captor
+ private lateinit var detectionCallback: ArgumentCaptor<FaceManager.FaceDetectionCallback>
+ @Captor private lateinit var cancellationSignal: ArgumentCaptor<CancellationSignal>
+ @Captor
+ private lateinit var faceLockoutResetCallback: ArgumentCaptor<FaceManager.LockoutResetCallback>
+ private lateinit var testDispatcher: TestDispatcher
+
+ private lateinit var testScope: TestScope
+ private lateinit var fakeUserRepository: FakeUserRepository
+ private lateinit var authStatus: FlowValue<AuthenticationStatus?>
+ private lateinit var detectStatus: FlowValue<DetectionStatus?>
+ private lateinit var authRunning: FlowValue<Boolean?>
+ private lateinit var lockedOut: FlowValue<Boolean?>
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeUserRepository = FakeUserRepository()
+ fakeUserRepository.setUserInfos(listOf(currentUser))
+ testDispatcher = StandardTestDispatcher()
+ testScope = TestScope(testDispatcher)
+ whenever(sessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(keyguardSessionId)
+ whenever(bypassController.bypassEnabled).thenReturn(true)
+ underTest = createFaceAuthManagerImpl(faceManager)
+ }
+
+ private fun createFaceAuthManagerImpl(
+ fmOverride: FaceManager? = faceManager,
+ bypassControllerOverride: KeyguardBypassController? = bypassController
+ ) =
+ KeyguardFaceAuthManagerImpl(
+ mContext,
+ fmOverride,
+ fakeUserRepository,
+ bypassControllerOverride,
+ testScope.backgroundScope,
+ testDispatcher,
+ sessionTracker,
+ uiEventLogger,
+ FaceAuthenticationLogger(logcatLogBuffer("KeyguardFaceAuthManagerLog")),
+ dumpManager,
+ )
+
+ @Test
+ fun faceAuthRunsAndProvidesAuthStatusUpdates() =
+ testScope.runTest {
+ testSetup(this)
+
+ FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER.extraInfo = 10
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+ uiEventIsLogged(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+
+ assertThat(authRunning()).isTrue()
+
+ val successResult = successResult()
+ authenticationCallback.value.onAuthenticationSucceeded(successResult)
+
+ assertThat(authStatus()).isEqualTo(SuccessAuthenticationStatus(successResult))
+
+ assertThat(authRunning()).isFalse()
+ }
+
+ private fun uiEventIsLogged(faceAuthUiEvent: FaceAuthUiEvent) {
+ verify(uiEventLogger)
+ .logWithInstanceIdAndPosition(
+ faceAuthUiEvent,
+ 0,
+ null,
+ keyguardSessionId,
+ faceAuthUiEvent.extraInfo
+ )
+ }
+
+ @Test
+ fun faceAuthDoesNotRunWhileItIsAlreadyRunning() =
+ testScope.runTest {
+ testSetup(this)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+ clearInvocations(faceManager)
+ clearInvocations(uiEventLogger)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ verifyNoMoreInteractions(faceManager)
+ verifyNoMoreInteractions(uiEventLogger)
+ }
+
+ @Test
+ fun faceLockoutStatusIsPropagated() =
+ testScope.runTest {
+ testSetup(this)
+ verify(faceManager).addLockoutResetCallback(faceLockoutResetCallback.capture())
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+
+ authenticationCallback.value.onAuthenticationError(
+ FACE_ERROR_LOCKOUT_PERMANENT,
+ "face locked out"
+ )
+
+ assertThat(lockedOut()).isTrue()
+
+ faceLockoutResetCallback.value.onLockoutReset(0)
+ assertThat(lockedOut()).isFalse()
+ }
+
+ @Test
+ fun faceDetectionSupportIsTheCorrectValue() =
+ testScope.runTest {
+ assertThat(createFaceAuthManagerImpl(fmOverride = null).isDetectionSupported).isFalse()
+
+ whenever(faceManager.sensorPropertiesInternal).thenReturn(null)
+ assertThat(createFaceAuthManagerImpl().isDetectionSupported).isFalse()
+
+ whenever(faceManager.sensorPropertiesInternal).thenReturn(listOf())
+ assertThat(createFaceAuthManagerImpl().isDetectionSupported).isFalse()
+
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = false)))
+ assertThat(createFaceAuthManagerImpl().isDetectionSupported).isFalse()
+
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(
+ listOf(
+ createFaceSensorProperties(supportsFaceDetection = false),
+ createFaceSensorProperties(supportsFaceDetection = true)
+ )
+ )
+ assertThat(createFaceAuthManagerImpl().isDetectionSupported).isFalse()
+
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(
+ listOf(
+ createFaceSensorProperties(supportsFaceDetection = true),
+ createFaceSensorProperties(supportsFaceDetection = false)
+ )
+ )
+ assertThat(createFaceAuthManagerImpl().isDetectionSupported).isTrue()
+ }
+
+ @Test
+ fun cancelStopsFaceAuthentication() =
+ testScope.runTest {
+ testSetup(this)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+
+ var wasAuthCancelled = false
+ cancellationSignal.value.setOnCancelListener { wasAuthCancelled = true }
+
+ underTest.cancel()
+ assertThat(wasAuthCancelled).isTrue()
+ assertThat(authRunning()).isFalse()
+ }
+
+ @Test
+ fun cancelInvokedWithoutFaceAuthRunningIsANoop() = testScope.runTest { underTest.cancel() }
+
+ @Test
+ fun faceDetectionRunsAndPropagatesDetectionStatus() =
+ testScope.runTest {
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = true)))
+ underTest = createFaceAuthManagerImpl()
+ testSetup(this)
+
+ underTest.detect()
+ faceDetectIsCalled()
+
+ detectionCallback.value.onFaceDetected(1, 1, true)
+
+ assertThat(detectStatus()).isEqualTo(DetectionStatus(1, 1, true))
+ }
+
+ @Test
+ fun faceDetectDoesNotRunIfDetectionIsNotSupported() =
+ testScope.runTest {
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = false)))
+ underTest = createFaceAuthManagerImpl()
+ testSetup(this)
+ clearInvocations(faceManager)
+
+ underTest.detect()
+
+ verify(faceManager, never()).detectFace(any(), any(), anyInt())
+ }
+
+ @Test
+ fun faceAuthShouldWaitAndRunIfTriggeredWhileCancelling() =
+ testScope.runTest {
+ testSetup(this)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+
+ // Enter cancelling state
+ underTest.cancel()
+ clearInvocations(faceManager)
+
+ // Auth is while cancelling.
+ underTest.authenticate(FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
+ // Auth is not started
+ verifyNoMoreInteractions(faceManager)
+
+ // Auth is done cancelling.
+ authenticationCallback.value.onAuthenticationError(
+ FACE_ERROR_CANCELED,
+ "First auth attempt cancellation completed"
+ )
+ assertThat(authStatus())
+ .isEqualTo(
+ ErrorAuthenticationStatus(
+ FACE_ERROR_CANCELED,
+ "First auth attempt cancellation completed"
+ )
+ )
+
+ faceAuthenticateIsCalled()
+ uiEventIsLogged(FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
+ }
+
+ @Test
+ fun faceAuthAutoCancelsAfterDefaultCancellationTimeout() =
+ testScope.runTest {
+ testSetup(this)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+
+ clearInvocations(faceManager)
+ underTest.cancel()
+ advanceTimeBy(KeyguardFaceAuthManagerImpl.DEFAULT_CANCEL_SIGNAL_TIMEOUT + 1)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+ }
+
+ @Test
+ fun faceHelpMessagesAreIgnoredBasedOnConfig() =
+ testScope.runTest {
+ overrideResource(
+ R.array.config_face_acquire_device_entry_ignorelist,
+ intArrayOf(10, 11)
+ )
+ underTest = createFaceAuthManagerImpl()
+ testSetup(this)
+
+ underTest.authenticate(FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER)
+ faceAuthenticateIsCalled()
+
+ authenticationCallback.value.onAuthenticationHelp(9, "help msg")
+ authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg")
+ authenticationCallback.value.onAuthenticationHelp(11, "Ignored help msg")
+
+ assertThat(authStatus()).isEqualTo(HelpAuthenticationStatus(9, "help msg"))
+ }
+
+ @Test
+ fun dumpDoesNotErrorOutWhenFaceManagerOrBypassControllerIsNull() =
+ testScope.runTest {
+ fakeUserRepository.setSelectedUserInfo(currentUser)
+ underTest.dump(PrintWriter(StringWriter()), emptyArray())
+
+ underTest =
+ createFaceAuthManagerImpl(fmOverride = null, bypassControllerOverride = null)
+ fakeUserRepository.setSelectedUserInfo(currentUser)
+
+ underTest.dump(PrintWriter(StringWriter()), emptyArray())
+ }
+
+ private suspend fun testSetup(testScope: TestScope) {
+ with(testScope) {
+ authStatus = collectLastValue(underTest.authenticationStatus)
+ detectStatus = collectLastValue(underTest.detectionStatus)
+ authRunning = collectLastValue(underTest.isAuthRunning)
+ lockedOut = collectLastValue(underTest.isLockedOut)
+ fakeUserRepository.setSelectedUserInfo(currentUser)
+ }
+ }
+
+ private fun successResult() = FaceManager.AuthenticationResult(null, null, currentUserId, false)
+
+ private fun faceDetectIsCalled() {
+ verify(faceManager)
+ .detectFace(
+ cancellationSignal.capture(),
+ detectionCallback.capture(),
+ eq(currentUserId)
+ )
+ }
+
+ private fun faceAuthenticateIsCalled() {
+ verify(faceManager)
+ .authenticate(
+ isNull(),
+ cancellationSignal.capture(),
+ authenticationCallback.capture(),
+ isNull(),
+ eq(currentUserId),
+ eq(true)
+ )
+ }
+
+ private fun createFaceSensorProperties(
+ supportsFaceDetection: Boolean
+ ): FaceSensorPropertiesInternal {
+ val componentInfo =
+ listOf(
+ ComponentInfoInternal(
+ "faceSensor" /* componentId */,
+ "vendor/model/revision" /* hardwareVersion */,
+ "1.01" /* firmwareVersion */,
+ "00000001" /* serialNumber */,
+ "" /* softwareVersion */
+ )
+ )
+ return FaceSensorPropertiesInternal(
+ 0 /* id */,
+ FaceSensorProperties.STRENGTH_STRONG,
+ 1 /* maxTemplatesAllowed */,
+ componentInfo,
+ FaceSensorProperties.TYPE_UNKNOWN,
+ supportsFaceDetection /* supportsFaceDetection */,
+ true /* supportsSelfIllumination */,
+ false /* resetLockoutRequiresChallenge */
+ )
+ }
+
+ companion object {
+ const val currentUserId = 1
+ val keyguardSessionId = fakeInstanceId(10)!!
+ val currentUser = UserInfo(currentUserId, "test user", 0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 8bb6a85..0469e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -324,29 +324,6 @@
}
@Test
- fun isBouncerShowing() =
- runTest(UnconfinedTestDispatcher()) {
- whenever(keyguardStateController.isBouncerShowing).thenReturn(false)
- var latest: Boolean? = null
- val job = underTest.isBouncerShowing.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isFalse()
-
- val captor = argumentCaptor<KeyguardStateController.Callback>()
- verify(keyguardStateController).addCallback(captor.capture())
-
- whenever(keyguardStateController.isBouncerShowing).thenReturn(true)
- captor.value.onBouncerShowingChanged()
- assertThat(latest).isTrue()
-
- whenever(keyguardStateController.isBouncerShowing).thenReturn(false)
- captor.value.onBouncerShowingChanged()
- assertThat(latest).isFalse()
-
- job.cancel()
- }
-
- @Test
fun isKeyguardGoingAway() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 7ded354..18e80ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -130,7 +130,7 @@
givenCanShowAlternateBouncer()
assertTrue(underTest.show())
- assertTrue(bouncerRepository.isAlternateBouncerVisible.value)
+ assertTrue(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -138,7 +138,7 @@
givenCannotShowAlternateBouncer()
assertFalse(underTest.show())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -146,7 +146,7 @@
bouncerRepository.setAlternateVisible(true)
assertTrue(underTest.hide())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -154,7 +154,7 @@
bouncerRepository.setAlternateVisible(false)
assertFalse(underTest.hide())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
private fun givenCanShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 7d4861b..153439e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.settings.DisplayTracker
@@ -38,7 +39,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
@@ -50,6 +50,7 @@
private lateinit var underTest: KeyguardInteractor
private lateinit var repository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
@Before
fun setUp() {
@@ -58,7 +59,14 @@
commandQueue = FakeCommandQueue(mock(Context::class.java), mock(DisplayTracker::class.java))
testScope = TestScope()
repository = FakeKeyguardRepository()
- underTest = KeyguardInteractor(repository, commandQueue, featureFlags)
+ bouncerRepository = FakeKeyguardBouncerRepository()
+ underTest =
+ KeyguardInteractor(
+ repository,
+ commandQueue,
+ featureFlags,
+ bouncerRepository,
+ )
}
@Test
@@ -137,7 +145,7 @@
repository.setKeyguardOccluded(true)
assertThat(secureCameraActive()).isTrue()
- repository.setBouncerShowing(true)
+ bouncerRepository.setPrimaryVisible(true)
assertThat(secureCameraActive()).isFalse()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 240af7b..23e06ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
@@ -298,6 +299,7 @@
repository = FakeKeyguardRepository(),
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry =
FakeKeyguardQuickAffordanceRegistry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index ec70857..1b8c627 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
@@ -159,7 +160,8 @@
KeyguardInteractor(
repository = repository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry =
FakeKeyguardQuickAffordanceRegistry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 46e4679..ae7a928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -22,7 +22,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositoryImpl
@@ -65,6 +67,7 @@
private lateinit var testScope: TestScope
private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
// Used to issue real transition steps for test input
@@ -81,6 +84,10 @@
private lateinit var fromOccludedTransitionInteractor: FromOccludedTransitionInteractor
private lateinit var fromGoneTransitionInteractor: FromGoneTransitionInteractor
private lateinit var fromAodTransitionInteractor: FromAodTransitionInteractor
+ private lateinit var fromAlternateBouncerTransitionInteractor:
+ FromAlternateBouncerTransitionInteractor
+ private lateinit var fromPrimaryBouncerTransitionInteractor:
+ FromPrimaryBouncerTransitionInteractor
@Before
fun setUp() {
@@ -88,6 +95,7 @@
testScope = TestScope()
keyguardRepository = FakeKeyguardRepository()
+ bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
/* Used to issue full transition steps, to better simulate a real device */
@@ -98,8 +106,7 @@
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
@@ -109,8 +116,7 @@
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -119,8 +125,7 @@
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -129,8 +134,7 @@
fromGoneTransitionInteractor =
FromGoneTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -139,8 +143,7 @@
fromDozingTransitionInteractor =
FromDozingTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -149,12 +152,29 @@
fromOccludedTransitionInteractor =
FromOccludedTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
fromOccludedTransitionInteractor.start()
+
+ fromAlternateBouncerTransitionInteractor =
+ FromAlternateBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromAlternateBouncerTransitionInteractor.start()
+
+ fromPrimaryBouncerTransitionInteractor =
+ FromPrimaryBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromPrimaryBouncerTransitionInteractor.start()
}
@Test
@@ -256,7 +276,7 @@
}
@Test
- fun `LOCKSCREEN to BOUNCER via bouncer showing call`() =
+ fun `LOCKSCREEN to PRIMARY_BOUNCER via bouncer showing call`() =
testScope.runTest {
// GIVEN a device that has at least woken up
keyguardRepository.setWakefulnessModel(startingToWake())
@@ -278,18 +298,18 @@
)
runCurrent()
- // WHEN the bouncer is set to show
- keyguardRepository.setBouncerShowing(true)
+ // WHEN the primary bouncer is set to show
+ bouncerRepository.setPrimaryVisible(true)
runCurrent()
val info =
withArgCaptor<TransitionInfo> {
verify(mockTransitionRepository).startTransition(capture())
}
- // THEN a transition to BOUNCER should occur
+ // THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
assertThat(info.animator).isNotNull()
coroutineContext.cancelChildren()
@@ -695,6 +715,297 @@
coroutineContext.cancelChildren()
}
+ @Test
+ fun `ALTERNATE_BOUNCER to PRIMARY_BOUNCER`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the alternateBouncer stops showing and then the primary bouncer shows
+ bouncerRepository.setPrimaryVisible(true)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to PRIMARY_BOUNCER should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to AOD`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing, aod available and starting to sleep
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setAodAvailable(true)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to DOZING`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
+ // to sleep
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setAodAvailable(false)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing and device not sleeping
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to LOCKSCREEN should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to AOD`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN aod available and starting to sleep
+ keyguardRepository.setAodAvailable(true)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the primaryBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to DOZING`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN aod not available and starting to sleep to sleep
+ keyguardRepository.setAodAvailable(false)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the primaryBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN device not sleeping
+ keyguardRepository.setWakefulnessModel(startingToWake())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to LOCKSCREEN should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
private fun startingToWake() =
WakefulnessModel(
WakefulnessState.STARTING_TO_WAKE,
@@ -710,4 +1021,13 @@
WakeSleepReason.OTHER,
WakeSleepReason.OTHER
)
+
+ private fun createKeyguardInteractor(featureFlags: FeatureFlags): KeyguardInteractor {
+ return KeyguardInteractor(
+ keyguardRepository,
+ commandQueue,
+ featureFlags,
+ bouncerRepository,
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index c5e0252..46ed829 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -102,7 +102,7 @@
verify(repository).setPrimaryScrimmed(true)
verify(repository).setPanelExpansion(EXPANSION_VISIBLE)
verify(repository).setPrimaryShowingSoon(true)
- verify(keyguardStateController).notifyBouncerShowing(true)
+ verify(keyguardStateController).notifyPrimaryBouncerShowing(true)
verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToShow()
verify(repository).setPrimaryVisible(true)
verify(repository).setPrimaryShow(any(KeyguardBouncerModel::class.java))
@@ -118,7 +118,7 @@
@Test
fun testShow_keyguardIsDone() {
`when`(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true)
- verify(keyguardStateController, never()).notifyBouncerShowing(true)
+ verify(keyguardStateController, never()).notifyPrimaryBouncerShowing(true)
verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow()
}
@@ -126,7 +126,7 @@
fun testHide() {
underTest.hide()
verify(falsingCollector).onBouncerHidden()
- verify(keyguardStateController).notifyBouncerShowing(false)
+ verify(keyguardStateController).notifyPrimaryBouncerShowing(false)
verify(repository).setPrimaryShowingSoon(false)
verify(repository).setPrimaryVisible(false)
verify(repository).setPrimaryHide(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 03a347e..6afeddd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
@@ -136,6 +137,7 @@
repository = repository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
)
whenever(userTracker.userHandle).thenReturn(mock())
whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index 57abae0..528978a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.dialog
+package com.android.systemui.qs.tiles
import android.os.Handler
import android.testing.AndroidTestingRunner
@@ -27,7 +27,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSTileHost
import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.qs.tiles.FontScalingTile
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import org.junit.Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
index 020a866..3fd19ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
@@ -30,12 +30,14 @@
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.nio.file.Files
import java.util.concurrent.Executor
-import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.isNull
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@@ -61,36 +63,83 @@
UserFileManagerImpl(context, userManager, broadcastDispatcher, backgroundExecutor)
}
- @After
- fun end() {
- val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID)
- dir.deleteRecursively()
- }
-
@Test
fun testGetFile() {
assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path)
.isEqualTo("${context.filesDir}/$TEST_FILE_NAME")
assertThat(userFileManager.getFile(TEST_FILE_NAME, 11).path)
- .isEqualTo("${context.filesDir}/${UserFileManagerImpl.ID}/11/files/$TEST_FILE_NAME")
+ .isEqualTo("${context.filesDir}/__USER_11_$TEST_FILE_NAME")
}
@Test
fun testGetSharedPreferences() {
+ val primarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0)
val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)
- val secondaryUserDir =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- UserFileManagerImpl.SHARED_PREFS,
- TEST_FILE_NAME
- )
- assertThat(secondarySharedPref).isNotNull()
- assertThat(secondaryUserDir.exists())
- assertThat(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0))
- .isNotEqualTo(secondarySharedPref)
+ assertThat(primarySharedPref).isNotEqualTo(secondarySharedPref)
+
+ // Make sure these are different files
+ primarySharedPref.edit().putString("TEST", "ABC").commit()
+ assertThat(secondarySharedPref.getString("TEST", null)).isNull()
+
+ context.deleteSharedPreferences("TEST")
+ context.deleteSharedPreferences("__USER_11_TEST")
+ }
+
+ @Test
+ fun testMigrateFile() {
+ val userId = 12
+ val fileName = "myFile.txt"
+ val fileContents = "TestingFile"
+ val legacyFile =
+ UserFileManagerImpl.createLegacyFile(
+ context,
+ UserFileManagerImpl.FILES,
+ fileName,
+ userId
+ )!!
+
+ // Write file to legacy area
+ Files.createDirectories(legacyFile.getParentFile().toPath())
+ Files.write(legacyFile.toPath(), fileContents.toByteArray())
+ assertThat(legacyFile.exists()).isTrue()
+
+ // getFile() should migrate the legacy file to the new location
+ val file = userFileManager.getFile(fileName, userId)
+ val newContents = String(Files.readAllBytes(file.toPath()))
+
+ assertThat(newContents).isEqualTo(fileContents)
+ assertThat(legacyFile.exists()).isFalse()
+ assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
+ }
+
+ @Test
+ fun testMigrateSharedPrefs() {
+ val userId = 13
+ val fileName = "myFile"
+ val contents = "TestingSharedPrefs"
+ val legacyFile =
+ UserFileManagerImpl.createLegacyFile(
+ context,
+ UserFileManagerImpl.SHARED_PREFS,
+ "$fileName.xml",
+ userId
+ )!!
+
+ // Write a valid shared prefs xml file to legacy area
+ val tmpPrefs = context.getSharedPreferences("tmp", Context.MODE_PRIVATE)
+ tmpPrefs.edit().putString(contents, contents).commit()
+ Files.createDirectories(legacyFile.getParentFile().toPath())
+ val tmpFile =
+ Environment.buildPath(context.dataDir, UserFileManagerImpl.SHARED_PREFS, "tmp.xml")
+ tmpFile.renameTo(legacyFile)
+ assertThat(legacyFile.exists()).isTrue()
+
+ // getSharedpreferences() should migrate the legacy file to the new location
+ val prefs = userFileManager.getSharedPreferences(fileName, Context.MODE_PRIVATE, userId)
+ assertThat(prefs.getString(contents, "")).isEqualTo(contents)
+ assertThat(legacyFile.exists()).isFalse()
+ assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
}
@Test
@@ -111,44 +160,14 @@
@Test
fun testClearDeletedUserData() {
- val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID, "11", "files")
- dir.mkdirs()
- val file =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- "files",
- TEST_FILE_NAME
- )
- val secondaryUserDir =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- )
+ val file = userFileManager.getFile(TEST_FILE_NAME, 11)
file.createNewFile()
- assertThat(secondaryUserDir.exists()).isTrue()
+
assertThat(file.exists()).isTrue()
userFileManager.clearDeletedUserData()
assertThat(backgroundExecutor.runAllReady()).isGreaterThan(0)
- verify(userManager).aliveUsers
- assertThat(secondaryUserDir.exists()).isFalse()
- assertThat(file.exists()).isFalse()
- }
+ verify(userManager, atLeastOnce()).aliveUsers
- @Test
- fun testEnsureParentDirExists() {
- val file =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- "files",
- TEST_FILE_NAME
- )
- assertThat(file.parentFile.exists()).isFalse()
- UserFileManagerImpl.ensureParentDirExists(file)
- assertThat(file.parentFile.exists()).isTrue()
+ assertThat(file.exists()).isFalse()
}
}
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 e5d5e3b..d229a08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -21,7 +21,7 @@
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardHostViewController
+import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R
@@ -106,7 +106,7 @@
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
- @Mock lateinit var keyguardHostViewController: KeyguardHostViewController
+ @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -122,8 +122,8 @@
.thenReturn(mock(ViewGroup::class.java))
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
.thenReturn(keyguardBouncerComponent)
- whenever(keyguardBouncerComponent.keyguardHostViewController)
- .thenReturn(keyguardHostViewController)
+ whenever(keyguardBouncerComponent.securityContainerController)
+ .thenReturn(keyguardSecurityContainerController)
underTest = NotificationShadeWindowViewController(
lockscreenShadeTransitionController,
FalsingCollectorFake(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 5cc3ef1..5e9c219 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -33,7 +33,7 @@
import androidx.test.filters.SmallTest;
-import com.android.keyguard.KeyguardHostViewController;
+import com.android.keyguard.KeyguardSecurityContainerController;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
@@ -97,7 +97,7 @@
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private KeyguardBouncerComponent mKeyguardBouncerComponent;
- @Mock private KeyguardHostViewController mKeyguardHostViewController;
+ @Mock private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -117,8 +117,8 @@
when(mView.findViewById(R.id.keyguard_bouncer_container)).thenReturn(mock(ViewGroup.class));
when(mKeyguardBouncerComponentFactory.create(any(ViewGroup.class))).thenReturn(
mKeyguardBouncerComponent);
- when(mKeyguardBouncerComponent.getKeyguardHostViewController()).thenReturn(
- mKeyguardHostViewController);
+ when(mKeyguardBouncerComponent.getSecurityContainerController()).thenReturn(
+ mKeyguardSecurityContainerController);
when(mStatusBarStateController.isDozing()).thenReturn(false);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
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 d01edcc..26eff61 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
@@ -230,7 +230,7 @@
}
@Test
- fun pluginRemoved_clockChanged() {
+ fun pluginRemoved_clockAndListChanged() {
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2")
@@ -239,20 +239,36 @@
.addClock("clock_3", "clock 3", { mockClock })
.addClock("clock_4", "clock 4")
- registry.applySettings(ClockSettings("clock_3", null))
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
var changeCallCount = 0
- registry.registerClockChangeListener { changeCallCount++ }
+ var listChangeCallCount = 0
+ registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() { changeCallCount++ }
+ override fun onAvailableClocksChanged() { listChangeCallCount++ }
+ })
+
+ registry.applySettings(ClockSettings("clock_3", null))
+ assertEquals(0, changeCallCount)
+ assertEquals(0, listChangeCallCount)
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ assertEquals(0, changeCallCount)
+ assertEquals(1, listChangeCallCount)
+
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ assertEquals(1, changeCallCount)
+ assertEquals(2, listChangeCallCount)
pluginListener.onPluginDisconnected(plugin1)
- assertEquals(0, changeCallCount)
+ assertEquals(1, changeCallCount)
+ assertEquals(3, listChangeCallCount)
pluginListener.onPluginDisconnected(plugin2)
- assertEquals(1, changeCallCount)
+ assertEquals(2, changeCallCount)
+ assertEquals(4, listChangeCallCount)
}
+
@Test
fun jsonDeserialization_gotExpectedObject() {
val expected = ClockSettings("ID", null).apply { _applied_timestamp = 500 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index c6207e5..413767a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar;
+import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
+
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static junit.framework.Assert.assertFalse;
@@ -28,6 +30,7 @@
import android.app.ActivityManager;
import android.app.Notification;
+import android.app.PendingIntent;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -42,6 +45,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import org.junit.After;
@@ -64,6 +68,7 @@
private static final int TEST_UID = 0;
protected static final int TEST_MINIMUM_DISPLAY_TIME = 200;
+ protected static final int TEST_STICKY_DISPLAY_TIME = 1000;
protected static final int TEST_AUTO_DISMISS_TIME = 500;
// Number of notifications to use in tests requiring multiple notifications
private static final int TEST_NUM_NOTIFICATIONS = 4;
@@ -85,6 +90,7 @@
private TestableAlertingNotificationManager(Handler handler) {
super(mock(HeadsUpManagerLogger.class), handler);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+ mStickyDisplayTime = TEST_STICKY_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
@@ -110,6 +116,20 @@
return new TestableAlertingNotificationManager(handler);
}
+ protected StatusBarNotification createNewSbn(int id, Notification n) {
+ return new StatusBarNotification(
+ TEST_PACKAGE_NAME /* pkg */,
+ TEST_PACKAGE_NAME,
+ id,
+ null /* tag */,
+ TEST_UID,
+ 0 /* initialPid */,
+ n,
+ new UserHandle(ActivityManager.getCurrentUser()),
+ null /* overrideGroupKey */,
+ 0 /* postTime */);
+ }
+
protected StatusBarNotification createNewSbn(int id, Notification.Builder n) {
return new StatusBarNotification(
TEST_PACKAGE_NAME /* pkg */,
@@ -132,6 +152,15 @@
return createNewSbn(id, n);
}
+ protected StatusBarNotification createStickySbn(int id) {
+ Notification stickyHun = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true)
+ .build();
+ stickyHun.flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
+ return createNewSbn(id, stickyHun);
+ }
+
@Before
public void setUp() {
mTestHandler = Handler.createAsync(Looper.myLooper());
@@ -171,6 +200,20 @@
}
@Test
+ public void testShowNotification_stickyHun_earliestRemovalTime() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createStickySbn(/* id= */ 0))
+ .build();
+ notifEntry.setCreationElapsedRealTime(0);
+
+ mAlertingNotificationManager.showNotification(notifEntry);
+
+ final long earliestRemovalTime = mAlertingNotificationManager
+ .getCalculatedEarliestRemovalTime(notifEntry.getKey());
+ assertEquals(TEST_STICKY_DISPLAY_TIME, earliestRemovalTime);
+ }
+
+ @Test
public void testRemoveNotification_removeDeferred() {
mAlertingNotificationManager.showNotification(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index d4add75..90f6201 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -21,6 +21,7 @@
import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -249,6 +250,36 @@
}
@Test
+ public void testIsStickyAndNotDemoted_noFlagAndDemoted_returnFalse() {
+ mEntry.getSbn().getNotification().flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
+ assertFalse(mEntry.isStickyAndNotDemoted());
+ }
+
+ @Test
+ public void testIsStickyAndNotDemoted_noFlagAndNotDemoted_demoteAndReturnFalse() {
+ mEntry.getSbn().getNotification().flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
+
+ assertFalse(mEntry.isStickyAndNotDemoted());
+ assertTrue(mEntry.isDemoted());
+ }
+
+ @Test
+ public void testIsStickyAndNotDemoted_hasFlagButAlreadyDemoted_returnFalse() {
+ mEntry.getSbn().getNotification().flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
+ mEntry.demoteStickyHun();
+
+ assertFalse(mEntry.isStickyAndNotDemoted());
+ }
+
+ @Test
+ public void testIsStickyAndNotDemoted_hasFlagAndNotDemoted_returnTrue() {
+ mEntry.getSbn().getNotification().flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
+
+ assertFalse(mEntry.isDemoted());
+ assertTrue(mEntry.isStickyAndNotDemoted());
+ }
+
+ @Test
public void notificationDataEntry_testIsLastMessageFromReply() {
Person.Builder person = new Person.Builder()
.setName("name")
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 5832569..4d9db8c 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
@@ -518,7 +518,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = false,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
algorithmState.visibleChildren.add(childHunView)
@@ -526,6 +526,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -545,7 +546,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = false,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
// Use half of the HUN's height as overlap
childHunView.viewState.yTranslation = (childHunView.viewState.height + 1 shr 1).toFloat()
@@ -555,6 +556,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -578,7 +580,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = true,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
// HUN doesn't overlap with QQS Panel
childHunView.viewState.yTranslation = ambientState.topPadding +
@@ -589,6 +591,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -608,7 +611,7 @@
val childHunView = createHunViewMock(
isShadeOpen = false,
fullyVisible = false,
- headerVisibleAmount = 0f,
+ headerVisibleAmount = 0f
)
childHunView.viewState.yTranslation = 0f
// Shade is closed, thus childHunView's headerVisibleAmount is 0
@@ -619,6 +622,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -638,7 +642,7 @@
val childHunView = createHunViewMock(
isShadeOpen = false,
fullyVisible = false,
- headerVisibleAmount = 0.5f,
+ headerVisibleAmount = 0.5f
)
childHunView.viewState.yTranslation = 0f
// Shade is being opened, thus childHunView's headerVisibleAmount is between 0 and 1
@@ -650,6 +654,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -664,7 +669,7 @@
private fun createHunViewMock(
isShadeOpen: Boolean,
fullyVisible: Boolean,
- headerVisibleAmount: Float,
+ headerVisibleAmount: Float
) =
mock<ExpandableNotificationRow>().apply {
val childViewStateMock = createHunChildViewState(isShadeOpen, fullyVisible)
@@ -675,10 +680,7 @@
}
- private fun createHunChildViewState(
- isShadeOpen: Boolean,
- fullyVisible: Boolean,
- ) =
+ private fun createHunChildViewState(isShadeOpen: Boolean, fullyVisible: Boolean) =
ExpandableViewState().apply {
// Mock the HUN's height with ambientState.topPadding +
// ambientState.stackTranslation
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
index a986777..c669c6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
@@ -53,7 +53,7 @@
}
@Override
- public boolean isBouncerShowing() {
+ public boolean isPrimaryBouncerShowing() {
return false;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index ccc57ad..ee7e082 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -18,6 +18,9 @@
import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
import static org.mockito.AdditionalAnswers.answerVoid;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -28,7 +31,6 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -38,6 +40,8 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -51,6 +55,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.SysuiTestCase;
@@ -90,9 +95,12 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -398,4 +406,40 @@
// THEN display should try wake up for the full screen intent
verify(mCentralSurfaces).wakeUpForFullScreenIntent();
}
+
+ @Test
+ public void testOnFullScreenIntentWhenDozing_logToStatsd() {
+ final int kTestUid = 12345;
+ final String kTestActivityName = "TestActivity";
+ // GIVEN entry that can has a full screen intent that can show
+ PendingIntent mockFullScreenIntent = mock(PendingIntent.class);
+ when(mockFullScreenIntent.getCreatorUid()).thenReturn(kTestUid);
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.name = kTestActivityName;
+ when(mockFullScreenIntent.queryIntentComponents(anyInt()))
+ .thenReturn(Arrays.asList(resolveInfo));
+ Notification.Builder nb = new Notification.Builder(mContext, "a")
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setFullScreenIntent(mockFullScreenIntent, true);
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0,
+ "tag" + System.currentTimeMillis(), 0, 0,
+ nb.build(), new UserHandle(0), null, 0);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH);
+ when(entry.getSbn()).thenReturn(sbn);
+ MockitoSession mockingSession = mockitoSession()
+ .mockStatic(FrameworkStatsLog.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // WHEN
+ mNotificationActivityStarter.launchFullScreenIntent(entry);
+
+ // THEN the full screen intent should be logged to statsd.
+ verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
+ kTestUid, kTestActivityName));
+ mockingSession.finishMocking();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
index 5a6bb30..ab888f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
@@ -18,9 +18,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.google.common.truth.Truth.assertThat
@@ -42,7 +42,7 @@
private lateinit var underTest: AirplaneModeViewModelImpl
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: TableLogBuffer
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
private lateinit var connectivityRepository: FakeConnectivityRepository
private lateinit var interactor: AirplaneModeInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index 521c67f..0145103 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,7 +53,7 @@
private lateinit var mockitoSession: MockitoSession
private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var carrierConfigManager: CarrierConfigManager
@Mock private lateinit var dumpManager: DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 4da2104..17502f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -33,8 +33,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.util.mockito.any
@@ -81,7 +81,7 @@
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var summaryLogger: TableLogBuffer
@Mock private lateinit var demoModeController: DemoModeController
@Mock private lateinit var dumpManager: DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index a294088a..b2577e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -65,8 +65,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.any
@@ -94,7 +94,7 @@
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
private val scope = CoroutineScope(IMMEDIATE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 8090205..09b7a66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -42,8 +42,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.mockito.any
@@ -86,7 +86,7 @@
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var summaryLogger: TableLogBuffer
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index bbca001..c51dbf1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -85,7 +85,6 @@
MobileIconsInteractorImpl(
connectionsRepository,
carrierConfigTracker,
- logger = mock(),
tableLogger = mock(),
connectivityRepository,
userSetupRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
new file mode 100644
index 0000000..86529dc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.pipeline.mobile.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+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.plugins.log.LogcatEchoTracker
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Test
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+
+@SmallTest
+class MobileInputLoggerTest : SysuiTestCase() {
+ private val buffer =
+ LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java)).create("buffer", 10)
+ private val logger = MobileInputLogger(buffer)
+
+ @Test
+ fun testLogNetworkCapsChange_bufferHasInfo() {
+ logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+
+ val expectedNetId = NET_1_ID.toString()
+ val expectedCaps = NET_1_CAPS.toString()
+
+ assertThat(actualString).contains("true")
+ assertThat(actualString).contains(expectedNetId)
+ assertThat(actualString).contains(expectedCaps)
+ }
+
+ @Test
+ fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
+ logger.logOnLost(NET_1)
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+
+ val expectedNetId = NET_1_ID.toString()
+
+ assertThat(actualString).contains(expectedNetId)
+ }
+
+ companion object {
+ private const val NET_1_ID = 100
+ private val NET_1 =
+ com.android.systemui.util.mockito.mock<Network>().also {
+ Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+ }
+ private val NET_1_CAPS =
+ NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ .build()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index d9268a2..4628f84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
@@ -51,7 +50,6 @@
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var constants: ConnectivityConstants
private val testDispatcher = UnconfinedTestDispatcher()
@@ -77,7 +75,6 @@
subscriptionIdsFlow,
interactor,
airplaneModeInteractor,
- logger,
constants,
testScope.backgroundScope,
statusBarPipelineFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
deleted file mode 100644
index 3dccbbf..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ /dev/null
@@ -1,141 +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.pipeline.shared
-
-import android.net.Network
-import android.net.NetworkCapabilities
-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.plugins.log.LogcatEchoTracker
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
-import com.google.common.truth.Truth.assertThat
-import java.io.PrintWriter
-import java.io.StringWriter
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-import org.mockito.Mockito
-import org.mockito.Mockito.mock
-
-@SmallTest
-class ConnectivityPipelineLoggerTest : SysuiTestCase() {
- private val buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java))
- .create("buffer", 10)
- private val logger = ConnectivityPipelineLogger(buffer)
-
- @Test
- fun testLogNetworkCapsChange_bufferHasInfo() {
- logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- val expectedNetId = NET_1_ID.toString()
- val expectedCaps = NET_1_CAPS.toString()
-
- assertThat(actualString).contains("true")
- assertThat(actualString).contains(expectedNetId)
- assertThat(actualString).contains(expectedCaps)
- }
-
- @Test
- fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
- logger.logOnLost(NET_1)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- val expectedNetId = NET_1_ID.toString()
-
- assertThat(actualString).contains(expectedNetId)
- }
-
- @Test
- fun logOutputChange_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
- val flow: Flow<Int?> = flowOf(1, null, 3)
-
- val job = flow
- .logOutputChange(logger, "testInts")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("1")
- assertThat(actualString).contains("null")
- assertThat(actualString).contains("3")
-
- job.cancel()
- }
-
- @Test
- fun logInputChange_unit_printsInputName() = runBlocking(IMMEDIATE) {
- val flow: Flow<Unit> = flowOf(Unit, Unit)
-
- val job = flow
- .logInputChange(logger, "testInputs")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("testInputs")
-
- job.cancel()
- }
-
- @Test
- fun logInputChange_any_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
- val flow: Flow<Any?> = flowOf(null, 2, "threeString")
-
- val job = flow
- .logInputChange(logger, "testInputs")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("null")
- assertThat(actualString).contains("2")
- assertThat(actualString).contains("threeString")
-
- job.cancel()
- }
-
- companion object {
- private const val NET_1_ID = 100
- private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
- Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
- }
- private val NET_1_CAPS = NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
- .build()
- private val IMMEDIATE = Dispatchers.Main.immediate
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
index 6dbee2f..496f090 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -19,7 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
@@ -52,7 +52,7 @@
@Mock private lateinit var connectivitySlots: ConnectivitySlots
@Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: ConnectivityInputLogger
private lateinit var scope: CoroutineScope
@Mock private lateinit var tunerService: TunerService
@@ -61,14 +61,15 @@
MockitoAnnotations.initMocks(this)
scope = CoroutineScope(IMMEDIATE)
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
}
@After
@@ -77,199 +78,179 @@
}
@Test
- fun forceHiddenSlots_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
- context.getOrCreateTestableResources().addOverride(
- DEFAULT_HIDDEN_ICONS_RESOURCE,
- arrayOf(SLOT_WIFI, SLOT_ETHERNET)
- )
- // Re-create our [ConnectivityRepositoryImpl], since it fetches
- // config_statusBarIconsToExclude when it's first constructed
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ fun forceHiddenSlots_initiallyGetsDefault() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context
+ .getOrCreateTestableResources()
+ .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET))
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_slotNamesAdded_flowHasSlots() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_wrongKey_doesNotUpdate() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_wrongKey_doesNotUpdate() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- // WHEN onTuningChanged with the wrong key
- getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
- yield()
+ // WHEN onTuningChanged with the wrong key
+ getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
+ yield()
- // THEN we didn't update our value and still have the old one
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ // THEN we didn't update our value and still have the old one
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
- context.getOrCreateTestableResources().addOverride(
- DEFAULT_HIDDEN_ICONS_RESOURCE,
- arrayOf(SLOT_WIFI, SLOT_ETHERNET)
- )
- // Re-create our [ConnectivityRepositoryImpl], since it fetches
- // config_statusBarIconsToExclude when it's first constructed
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context
+ .getOrCreateTestableResources()
+ .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET))
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- // First, update the slots
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ // First, update the slots
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- // WHEN we update to a null value
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
- yield()
+ // WHEN we update to a null value
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
+ yield()
- // THEN we go back to our default value
- assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+ // THEN we go back to our default value
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() =
+ runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
- .thenReturn(ConnectivitySlot.WIFI)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
- assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- // WHEN there's empty and blank slot names
- getTunable().onTuningChanged(
- HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI"
- )
+ // WHEN there's empty and blank slot names
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI")
- // THEN we skip that slot but still process the other ones
- assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
+ // THEN we skip that slot but still process the other ones
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = runBlocking(IMMEDIATE) {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() =
+ runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
- whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
- getTunable().onTuningChanged(
- HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
- )
+ getTunable()
+ .onTuningChanged(
+ HIDDEN_ICONS_TUNABLE_KEY,
+ "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
+ )
- assertThat(latest).isEmpty()
+ assertThat(latest).isEmpty()
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_newSubscriberGetsCurrentValue() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_newSubscriberGetsCurrentValue() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest1: Set<ConnectivitySlot>? = null
- val job1 = underTest
- .forceHiddenSlots
- .onEach { latest1 = it }
- .launchIn(this)
+ var latest1: Set<ConnectivitySlot>? = null
+ val job1 = underTest.forceHiddenSlots.onEach { latest1 = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
- assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+ assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
- // WHEN we add a second subscriber after having already emitted a value
- var latest2: Set<ConnectivitySlot>? = null
- val job2 = underTest
- .forceHiddenSlots
- .onEach { latest2 = it }
- .launchIn(this)
+ // WHEN we add a second subscriber after having already emitted a value
+ var latest2: Set<ConnectivitySlot>? = null
+ val job2 = underTest.forceHiddenSlots.onEach { latest2 = it }.launchIn(this)
- // THEN the second subscribe receives the already-emitted value
- assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+ // THEN the second subscribe receives the already-emitted value
+ assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
- job1.cancel()
- job2.cancel()
- }
+ job1.cancel()
+ job2.cancel()
+ }
private fun getTunable(): TunerService.Tunable {
val callbackCaptor = argumentCaptor<TunerService.Tunable>()
@@ -280,10 +261,8 @@
private fun setUpEthernetWifiMobileSlotNames() {
whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET))
.thenReturn(ConnectivitySlot.ETHERNET)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
- .thenReturn(ConnectivitySlot.WIFI)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE))
- .thenReturn(ConnectivitySlot.MOBILE)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(ConnectivitySlot.MOBILE)
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index 1085c2b..25678b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -23,11 +23,11 @@
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
@@ -47,6 +47,7 @@
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@SmallTest
class WifiRepositorySwitcherTest : SysuiTestCase() {
private lateinit var underTest: WifiRepositorySwitcher
@@ -54,7 +55,7 @@
private lateinit var demoImpl: DemoWifiRepository
@Mock private lateinit var demoModeController: DemoModeController
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: WifiInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index db791bb..c7b31bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -34,9 +34,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -72,7 +72,7 @@
private lateinit var underTest: WifiRepositoryImpl
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: WifiInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 60f564e..64810d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -36,7 +36,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
@@ -63,7 +62,6 @@
private lateinit var testableLooper: TestableLooper
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -92,7 +90,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
viewModel =
@@ -100,7 +98,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index 648d7a5..12b1664 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -33,7 +33,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
@@ -68,7 +67,6 @@
private lateinit var underTest: WifiViewModel
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -94,7 +92,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
}
@@ -125,7 +123,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 45ebb39..7a62cb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
@@ -59,7 +58,6 @@
private lateinit var underTest: WifiViewModel
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -85,7 +83,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
@@ -478,7 +476,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 4aa86c2..13a2baa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -20,6 +20,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -81,6 +82,7 @@
UiEventLogger uiEventLogger) {
super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+ mStickyDisplayTime = TEST_STICKY_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
}
@@ -129,6 +131,86 @@
assertFalse(mHeadsUpManager.isAlerting(mEntry.getKey()));
}
+
+ @Test
+ public void testIsSticky_rowPinnedAndExpanded_true() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ when(mRow.isPinned()).thenReturn(true);
+ notifEntry.setRow(mRow);
+
+ mHeadsUpManager.showNotification(notifEntry);
+
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+ headsUpEntry.setExpanded(true);
+
+ assertTrue(mHeadsUpManager.isSticky(notifEntry.getKey()));
+ }
+
+ @Test
+ public void testIsSticky_remoteInputActive_true() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ mHeadsUpManager.showNotification(notifEntry);
+
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+
+ headsUpEntry.remoteInputActive = true;
+
+ assertTrue(mHeadsUpManager.isSticky(notifEntry.getKey()));
+ }
+
+ @Test
+ public void testIsSticky_hasFullScreenIntent_true() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ mHeadsUpManager.showNotification(notifEntry);
+
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+
+ notifEntry.getSbn().getNotification().fullScreenIntent = PendingIntent.getActivity(
+ getContext(), 0, new Intent(getContext(), this.getClass()),
+ PendingIntent.FLAG_MUTABLE_UNAUDITED);
+
+ assertTrue(mHeadsUpManager.isSticky(notifEntry.getKey()));
+ }
+
+ @Test
+ public void testIsSticky_stickyAndNotDemoted_true() {
+ NotificationEntry alertEntry = new NotificationEntryBuilder()
+ .setSbn(createStickySbn(0))
+ .build();
+
+ mHeadsUpManager.showNotification(alertEntry);
+
+ assertTrue(mHeadsUpManager.isSticky(alertEntry.getKey()));
+ }
+
+ @Test
+ public void testIsSticky_false() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ mHeadsUpManager.showNotification(notifEntry);
+
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+ headsUpEntry.setExpanded(false);
+ headsUpEntry.remoteInputActive = false;
+
+ assertFalse(mHeadsUpManager.isSticky(notifEntry.getKey()));
+ }
+
@Test
public void testCompareTo_withNullEntries() {
NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
index 48a2e09..f8bf4b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -29,7 +29,9 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito.times
import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -59,21 +61,16 @@
@Mock lateinit var bluetoothAdapter: BluetoothAdapter
@Mock lateinit var bluetoothDevice: BluetoothDevice
@Mock lateinit var handler: Handler
-
@Mock lateinit var featureFlags: FeatureFlags
-
@Mock lateinit var uiEventLogger: UiEventLogger
-
@Mock lateinit var stylusCallback: StylusManager.StylusCallback
-
@Mock lateinit var otherStylusCallback: StylusManager.StylusCallback
-
@Mock lateinit var stylusBatteryCallback: StylusManager.StylusBatteryCallback
-
@Mock lateinit var otherStylusBatteryCallback: StylusManager.StylusBatteryCallback
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var stylusManager: StylusManager
+ private val instanceIdSequenceFake = InstanceIdSequenceFake(10)
@Before
fun setUp() {
@@ -100,6 +97,8 @@
uiEventLogger
)
+ stylusManager.instanceIdSequence = instanceIdSequenceFake
+
whenever(otherDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(false)
whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
@@ -403,7 +402,13 @@
fun onStylusBluetoothConnected_logsEvent() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
- verify(uiEventLogger, times(1)).log(StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED)
+ verify(uiEventLogger, times(1))
+ .logWithInstanceId(
+ StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED,
+ 0,
+ null,
+ InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId)
+ )
}
@Test
@@ -416,12 +421,16 @@
}
@Test
- fun onStylusBluetoothDisconnected_logsEvent() {
+ fun onStylusBluetoothDisconnected_logsEventInSameSession() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+ val instanceId = InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId)
stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID)
- verify(uiEventLogger, times(1)).log(StylusUiEvent.BLUETOOTH_STYLUS_DISCONNECTED)
+ verify(uiEventLogger, times(1))
+ .logWithInstanceId(StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED, 0, null, instanceId)
+ verify(uiEventLogger, times(1))
+ .logWithInstanceId(StylusUiEvent.BLUETOOTH_STYLUS_DISCONNECTED, 0, null, instanceId)
}
@Test
@@ -519,7 +528,12 @@
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
verify(uiEventLogger, times(1))
- .log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
+ .logWithInstanceId(
+ StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED,
+ 0,
+ null,
+ InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId)
+ )
}
@Test
@@ -530,7 +544,7 @@
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
- verify(uiEventLogger, never()).log(any())
+ verifyZeroInteractions(uiEventLogger)
}
@Test
@@ -539,18 +553,33 @@
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
- verify(uiEventLogger, never()).log(any())
+ verifyZeroInteractions(uiEventLogger)
}
@Test
fun onBatteryStateChanged_batteryAbsent_inUsiSession_logSessionEnd() {
whenever(batteryState.isPresent).thenReturn(true)
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+ val instanceId = InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId)
whenever(batteryState.isPresent).thenReturn(false)
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
- verify(uiEventLogger, times(1)).log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+ verify(uiEventLogger, times(1))
+ .logWithInstanceId(
+ StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED,
+ 0,
+ null,
+ instanceId
+ )
+
+ verify(uiEventLogger, times(1))
+ .logWithInstanceId(
+ StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED,
+ 0,
+ null,
+ instanceId
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
index d51c514..572aca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
@@ -28,7 +28,9 @@
import android.view.InputDevice
import androidx.core.app.NotificationManagerCompat
import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -64,13 +66,14 @@
@Mock lateinit var btStylusDevice: InputDevice
@Mock lateinit var uiEventLogger: UiEventLogger
-
@Captor lateinit var notificationCaptor: ArgumentCaptor<Notification>
private lateinit var stylusUsiPowerUi: StylusUsiPowerUI
private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var contextSpy: Context
+ private val instanceIdSequenceFake = InstanceIdSequenceFake(10)
+
private val uid = ActivityManager.getCurrentUser()
@Before
@@ -92,6 +95,8 @@
stylusUsiPowerUi =
StylusUsiPowerUI(contextSpy, notificationManager, inputManager, handler, uiEventLogger)
+ stylusUsiPowerUi.instanceIdSequence = instanceIdSequenceFake
+
broadcastReceiver = stylusUsiPowerUi.receiver
}
@@ -212,10 +217,11 @@
stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
verify(uiEventLogger, times(1))
- .logWithPosition(
+ .logWithInstanceIdAndPosition(
StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_SHOWN,
uid,
contextSpy.packageName,
+ InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId),
10
)
}
@@ -250,10 +256,11 @@
broadcastReceiver.onReceive(contextSpy, intent)
verify(uiEventLogger, times(1))
- .logWithPosition(
+ .logWithInstanceIdAndPosition(
StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_CLICKED,
uid,
contextSpy.packageName,
+ InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId),
100
)
}
@@ -264,10 +271,11 @@
broadcastReceiver.onReceive(contextSpy, intent)
verify(uiEventLogger, times(1))
- .logWithPosition(
+ .logWithInstanceIdAndPosition(
StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_DISMISSED,
uid,
contextSpy.packageName,
+ InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId),
100
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 3d75967..a87e61a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.NotificationPanelViewController
@@ -112,7 +113,8 @@
KeyguardInteractor(
repository = keyguardRepository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
)
// Needs to be run on the main thread
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 22d05bf..f0a53ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -38,6 +38,7 @@
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.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -145,6 +146,7 @@
repository = keyguardRepository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 2f05e65..bc0881c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -251,6 +252,7 @@
repository = keyguardRepository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
featureFlags = featureFlags,
manager = manager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 9268904..c8b0496 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -152,7 +153,8 @@
KeyguardInteractor(
repository = keyguardRepository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
featureFlags = featureFlags,
manager = manager,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
index d0383e9..3374219 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
@@ -57,10 +57,10 @@
override val bouncerPromptReason = 0
override val bouncerErrorMessage: CharSequence? = null
private val _isAlternateBouncerVisible = MutableStateFlow(false)
- override val isAlternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
+ override val alternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
override var lastAlternateBouncerVisibleTime: Long = 0L
private val _isAlternateBouncerUIAvailable = MutableStateFlow<Boolean>(false)
- override val isAlternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
+ override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
override fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 065fe89..1a371c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -84,9 +84,6 @@
private val _isUdfpsSupported = MutableStateFlow(false)
- private val _isBouncerShowing = MutableStateFlow(false)
- override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing
-
private val _isKeyguardGoingAway = MutableStateFlow(false)
override val isKeyguardGoingAway: Flow<Boolean> = _isKeyguardGoingAway
@@ -153,10 +150,6 @@
_wakefulnessModel.value = model
}
- fun setBouncerShowing(isShowing: Boolean) {
- _isBouncerShowing.value = isShowing
- }
-
fun setBiometricUnlockState(state: BiometricUnlockModel) {
_biometricUnlockState.tryEmit(state)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 95b62a1..bdf1aff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -49,7 +49,7 @@
}
@Override
- public boolean isBouncerShowing() {
+ public boolean isPrimaryBouncerShowing() {
return false;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 72c5598..328b971 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3819,20 +3819,30 @@
+ "proxy-ed");
}
- mProxyManager.registerProxy(client, displayId, mContext,
- sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
- mWindowManagerService, mA11yWindowManager);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mProxyManager.registerProxy(client, displayId, mContext,
+ sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
+ mWindowManagerService, mA11yWindowManager);
- synchronized (mLock) {
- notifyClearAccessibilityCacheLocked();
+ synchronized (mLock) {
+ notifyClearAccessibilityCacheLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
return true;
}
@Override
- public boolean unregisterProxyForDisplay(int displayId) throws RemoteException {
+ public boolean unregisterProxyForDisplay(int displayId) {
mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
- return mProxyManager.unregisterProxy(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mProxyManager.unregisterProxy(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
boolean isDisplayProxyed(int displayId) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index d7c5b5d..f8ab0d5 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -38,6 +38,7 @@
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.Message;
+import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.MathUtils;
@@ -48,6 +49,7 @@
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.View;
+import android.view.WindowManager;
import android.view.accessibility.MagnificationAnimationCallback;
import android.view.animation.DecelerateInterpolator;
@@ -62,6 +64,7 @@
import com.android.server.wm.WindowManagerInternal;
import java.util.Locale;
+import java.util.function.Supplier;
/**
* This class is used to control and query the state of display magnification
@@ -104,6 +107,8 @@
private boolean mAlwaysOnMagnificationEnabled = false;
private final DisplayManagerInternal mDisplayManagerInternal;
+ @NonNull private final Supplier<MagnificationThumbnail> mThumbnailSupplier;
+
/**
* This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
* magnification information per display.
@@ -134,6 +139,8 @@
private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
private boolean mMagnificationActivated = false;
+ @GuardedBy("mLock") @Nullable private MagnificationThumbnail mMagnificationThumbnail;
+
DisplayMagnification(int displayId) {
mDisplayId = displayId;
mSpecAnimationBridge = new SpecAnimationBridge(mControllerCtx, mLock, mDisplayId);
@@ -166,6 +173,11 @@
mControllerCtx.getWindowManager().getMagnificationRegion(
mDisplayId, mMagnificationRegion);
mMagnificationRegion.getBounds(mMagnificationBounds);
+
+ if (mMagnificationThumbnail == null) {
+ mMagnificationThumbnail = mThumbnailSupplier.get();
+ }
+
return true;
}
@@ -191,6 +203,8 @@
mMagnificationRegion.setEmpty();
mRegistered = false;
unregisterCallbackLocked(mDisplayId, delete);
+
+ destroyThumbNail();
}
mUnregisterPending = false;
}
@@ -327,6 +341,9 @@
if (!mMagnificationRegion.equals(magnified)) {
mMagnificationRegion.set(magnified);
mMagnificationRegion.getBounds(mMagnificationBounds);
+
+ refreshThumbNail(getScale(), getCenterX(), getCenterY());
+
// It's possible that our magnification spec is invalid with the new bounds.
// Adjust the current spec's offsets if necessary.
if (updateCurrentSpecWithOffsetsLocked(
@@ -368,18 +385,25 @@
@GuardedBy("mLock")
void onMagnificationChangedLocked() {
final float scale = getScale();
-
+ final float centerX = getCenterX();
+ final float centerY = getCenterY();
final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_FULLSCREEN)
.setActivated(mMagnificationActivated)
.setScale(scale)
- .setCenterX(getCenterX())
- .setCenterY(getCenterY()).build();
+ .setCenterX(centerX)
+ .setCenterY(centerY).build();
mMagnificationInfoChangedCallback.onFullScreenMagnificationChanged(mDisplayId,
mMagnificationRegion, config);
if (mUnregisterPending && !isActivated()) {
unregister(mDeleteAfterUnregister);
}
+
+ if (isActivated()) {
+ updateThumbNail(scale, centerX, centerY);
+ } else {
+ hideThumbNail();
+ }
}
@GuardedBy("mLock")
@@ -506,6 +530,9 @@
}
mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
sendSpecToAnimation(spec, animationCallback);
+
+ hideThumbNail();
+
return changed;
}
@@ -559,6 +586,40 @@
return changed;
}
+ @GuardedBy("mLock")
+ void updateThumbNail(float scale, float centerX, float centerY) {
+ if (mMagnificationThumbnail != null) {
+ mMagnificationThumbnail.updateThumbNail(scale, centerX, centerY);
+ }
+ }
+
+ @GuardedBy("mLock")
+ void refreshThumbNail(float scale, float centerX, float centerY) {
+ if (mMagnificationThumbnail != null) {
+ mMagnificationThumbnail.setThumbNailBounds(
+ mMagnificationBounds,
+ scale,
+ centerX,
+ centerY
+ );
+ }
+ }
+
+ @GuardedBy("mLock")
+ void hideThumbNail() {
+ if (mMagnificationThumbnail != null) {
+ mMagnificationThumbnail.hideThumbNail();
+ }
+ }
+
+ @GuardedBy("mLock")
+ void destroyThumbNail() {
+ if (mMagnificationThumbnail != null) {
+ hideThumbNail();
+ mMagnificationThumbnail = null;
+ }
+ }
+
/**
* Updates the current magnification spec.
*
@@ -688,21 +749,40 @@
@NonNull AccessibilityTraceManager traceManager, @NonNull Object lock,
@NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback,
@NonNull MagnificationScaleProvider scaleProvider) {
- this(new ControllerContext(context, traceManager,
- LocalServices.getService(WindowManagerInternal.class),
- new Handler(context.getMainLooper()),
- context.getResources().getInteger(R.integer.config_longAnimTime)), lock,
- magnificationInfoChangedCallback, scaleProvider);
+ this(
+ new ControllerContext(
+ context,
+ traceManager,
+ LocalServices.getService(WindowManagerInternal.class),
+ new Handler(context.getMainLooper()),
+ context.getResources().getInteger(R.integer.config_longAnimTime)),
+ lock,
+ magnificationInfoChangedCallback,
+ scaleProvider,
+ () -> {
+ if (DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACCESSIBILITY,
+ "enable_magnifier_thumbnail",
+ /* defaultValue= */ false)) {
+ return new MagnificationThumbnail(
+ context,
+ context.getSystemService(WindowManager.class),
+ new Handler(context.getMainLooper())
+ );
+ }
+
+ return null;
+ });
}
- /**
- * Constructor for tests
- */
+ /** Constructor for tests */
@VisibleForTesting
- public FullScreenMagnificationController(@NonNull ControllerContext ctx,
+ public FullScreenMagnificationController(
+ @NonNull ControllerContext ctx,
@NonNull Object lock,
@NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback,
- @NonNull MagnificationScaleProvider scaleProvider) {
+ @NonNull MagnificationScaleProvider scaleProvider,
+ @NonNull Supplier<MagnificationThumbnail> thumbnailSupplier) {
mControllerCtx = ctx;
mLock = lock;
mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId();
@@ -710,6 +790,7 @@
mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
mScaleProvider = scaleProvider;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+ mThumbnailSupplier = thumbnailSupplier;
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java
new file mode 100644
index 0000000..fe7b11f
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java
@@ -0,0 +1,305 @@
+/*
+ * 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.accessibility.magnification;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.annotation.AnyThread;
+import android.annotation.MainThread;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.R;
+/**
+ * This class is used to show of magnification thumbnail
+ * from FullScreenMagnification. It is responsible for
+ * show of magnification and fade in/out animation, and
+ * it just only uses in FullScreenMagnification
+ */
+public class MagnificationThumbnail {
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "MagnificationThumbnail";
+
+ private static final int FADE_IN_ANIMATION_DURATION_MS = 200;
+ private static final int FADE_OUT_ANIMATION_DURATION_MS = 1000;
+ private static final int LINGER_DURATION_MS = 500;
+
+ private Rect mWindowBounds;
+ private final Context mContext;
+ private final WindowManager mWindowManager;
+ private final Handler mHandler;
+
+ @VisibleForTesting
+ public final FrameLayout mThumbnailLayout;
+
+ private final View mThumbNailView;
+
+ private final WindowManager.LayoutParams mBackgroundParams;
+ private boolean mVisible = false;
+
+ private static final float ASPECT_RATIO = 28f;
+ private static final float BG_ASPECT_RATIO = ASPECT_RATIO / 2f;
+
+ private ObjectAnimator mThumbNailAnimator;
+ private boolean mIsFadingIn;
+
+ /**
+ * FullScreenMagnificationThumbnail Constructor
+ */
+ public MagnificationThumbnail(Context context, WindowManager windowManager, Handler handler) {
+ mContext = context;
+ mWindowManager = windowManager;
+ mHandler = handler;
+ mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mThumbnailLayout = (FrameLayout) LayoutInflater.from(mContext)
+ .inflate(R.layout.thumbnail_background_view, /* root: */ null);
+ mThumbNailView =
+ mThumbnailLayout.findViewById(R.id.accessibility_magnification_thumbnail_view);
+ mBackgroundParams = createLayoutParams();
+ }
+
+ /**
+ * Sets the magnificationBounds for Thumbnail and resets the position on the screen.
+ *
+ * @param currentBounds the current magnification bounds
+ */
+ @AnyThread
+ public void setThumbNailBounds(Rect currentBounds, float scale, float centerX, float centerY) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "setThumbNailBounds " + currentBounds);
+ }
+ mHandler.post(() -> {
+ mWindowBounds = currentBounds;
+ setBackgroundBounds();
+ if (mVisible) {
+ updateThumbNailMainThread(scale, centerX, centerY);
+ }
+ });
+ }
+
+ private void setBackgroundBounds() {
+ Point magnificationBoundary = getMagnificationThumbnailPadding(mContext);
+ final int thumbNailWidth = (int) (mWindowBounds.width() / BG_ASPECT_RATIO);
+ final int thumbNailHeight = (int) (mWindowBounds.height() / BG_ASPECT_RATIO);
+ int initX = magnificationBoundary.x;
+ int initY = magnificationBoundary.y;
+ mBackgroundParams.width = thumbNailWidth;
+ mBackgroundParams.height = thumbNailHeight;
+ mBackgroundParams.x = initX;
+ mBackgroundParams.y = initY;
+ }
+
+ @MainThread
+ private void showThumbNail() {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "showThumbNail " + mVisible);
+ }
+ animateThumbnail(true);
+ }
+
+ /**
+ * Hides thumbnail and removes the view from the window when finished animating.
+ */
+ @AnyThread
+ public void hideThumbNail() {
+ mHandler.post(this::hideThumbNailMainThread);
+ }
+
+ @MainThread
+ private void hideThumbNailMainThread() {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "hideThumbNail " + mVisible);
+ }
+ if (mVisible) {
+ animateThumbnail(false);
+ }
+ }
+
+ /**
+ * Animates the thumbnail in or out and resets the timeout to auto-hiding.
+ *
+ * @param fadeIn true: fade in, false fade out
+ */
+ @MainThread
+ private void animateThumbnail(boolean fadeIn) {
+ if (DEBUG) {
+ Log.d(
+ LOG_TAG,
+ "setThumbnailAnimation "
+ + " fadeIn: " + fadeIn
+ + " mVisible: " + mVisible
+ + " isFadingIn: " + mIsFadingIn
+ + " isRunning: " + mThumbNailAnimator
+ );
+ }
+
+ // Reset countdown to hide automatically
+ mHandler.removeCallbacks(this::hideThumbNailMainThread);
+ if (fadeIn) {
+ mHandler.postDelayed(this::hideThumbNailMainThread, LINGER_DURATION_MS);
+ }
+
+ if (fadeIn == mIsFadingIn) {
+ return;
+ }
+ mIsFadingIn = fadeIn;
+
+ if (fadeIn && !mVisible) {
+ mWindowManager.addView(mThumbnailLayout, mBackgroundParams);
+ mVisible = true;
+ }
+
+ if (mThumbNailAnimator != null) {
+ mThumbNailAnimator.cancel();
+ }
+ mThumbNailAnimator = ObjectAnimator.ofFloat(
+ mThumbnailLayout,
+ "alpha",
+ fadeIn ? 1f : 0f
+ );
+ mThumbNailAnimator.setDuration(
+ fadeIn ? FADE_IN_ANIMATION_DURATION_MS : FADE_OUT_ANIMATION_DURATION_MS
+ );
+ mThumbNailAnimator.addListener(new Animator.AnimatorListener() {
+ private boolean mIsCancelled;
+
+ @Override
+ public void onAnimationStart(@NonNull Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation) {
+ if (DEBUG) {
+ Log.d(
+ LOG_TAG,
+ "onAnimationEnd "
+ + " fadeIn: " + fadeIn
+ + " mVisible: " + mVisible
+ + " mIsCancelled: " + mIsCancelled
+ + " animation: " + animation);
+ }
+ if (mIsCancelled) {
+ return;
+ }
+ if (!fadeIn && mVisible) {
+ mWindowManager.removeView(mThumbnailLayout);
+ mVisible = false;
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(@NonNull Animator animation) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "onAnimationCancel "
+ + " fadeIn: " + fadeIn
+ + " mVisible: " + mVisible
+ + " animation: " + animation);
+ }
+ mIsCancelled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(@NonNull Animator animation) {
+
+ }
+ });
+
+ mThumbNailAnimator.start();
+ }
+
+ /**
+ * Scale up/down the current magnification thumbnail spec.
+ *
+ * <p>Will show/hide the thumbnail with animations when appropriate.
+ *
+ * @param scale the magnification scale
+ * @param centerX the unscaled, screen-relative X coordinate of the center
+ * of the viewport, or {@link Float#NaN} to leave unchanged
+ * @param centerY the unscaled, screen-relative Y coordinate of the center
+ * of the viewport, or {@link Float#NaN} to leave unchanged
+ */
+ @AnyThread
+ public void updateThumbNail(float scale, float centerX, float centerY) {
+ mHandler.post(() -> updateThumbNailMainThread(scale, centerX, centerY));
+ }
+
+ @MainThread
+ private void updateThumbNailMainThread(float scale, float centerX, float centerY) {
+ // Restart the fadeout countdown (or show if it's hidden)
+ showThumbNail();
+
+ var scaleDown = Float.isNaN(scale) ? mThumbNailView.getScaleX() : 1f / scale;
+ if (!Float.isNaN(scale)) {
+ mThumbNailView.setScaleX(scaleDown);
+ mThumbNailView.setScaleY(scaleDown);
+ }
+ if (!Float.isNaN(centerX)) {
+ var ratio = 1f / BG_ASPECT_RATIO;
+ var centerXScaled = centerX * ratio - mThumbNailView.getWidth() / 2f;
+ var centerYScaled = centerY * ratio - mThumbNailView.getHeight() / 2f;
+
+ if (DEBUG) {
+ Log.d(
+ LOG_TAG,
+ "updateThumbNail centerXScaled : " + centerXScaled
+ + " centerYScaled : " + centerYScaled
+ + " getTranslationX : " + mThumbNailView.getTranslationX()
+ + " ratio : " + ratio
+ );
+ }
+
+ mThumbNailView.setTranslationX(centerXScaled);
+ mThumbNailView.setTranslationY(centerYScaled);
+ }
+ }
+
+ private WindowManager.LayoutParams createLayoutParams() {
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
+ PixelFormat.TRANSPARENT);
+ params.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+ params.gravity = Gravity.BOTTOM | Gravity.LEFT;
+ params.setFitInsetsTypes(WindowInsets.Type.ime() | WindowInsets.Type.navigationBars());
+ return params;
+ }
+
+ private Point getMagnificationThumbnailPadding(Context context) {
+ Point thumbnailPaddings = new Point(0, 0);
+ final int defaultPadding = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.accessibility_magnification_thumbnail_padding);
+ thumbnailPaddings.x = defaultPadding;
+ thumbnailPaddings.y = defaultPadding;
+ return thumbnailPaddings;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index dc475f6..3a7aa85 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -158,19 +158,19 @@
/**
* The user that the backup is activated by default for.
*
- * If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will be
- * {@link UserHandle#USER_SYSTEM}.
+ * <p>If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will
+ * be {@link UserHandle#USER_SYSTEM}.
+ *
+ * <p>Note: on the first ever boot of a new device, this might change once the first user is
+ * unlocked. See {@link #updateDefaultBackupUserIdIfNeeded()}.
*
* @see #isBackupActivatedForUser(int)
*/
- @UserIdInt private final int mDefaultBackupUserId;
+ @UserIdInt private int mDefaultBackupUserId;
+
+ private boolean mHasFirstUserUnlockedSinceBoot = false;
public BackupManagerService(Context context) {
- this(context, new SparseArray<>());
- }
-
- @VisibleForTesting
- BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) {
mContext = context;
mGlobalDisable = isBackupDisabled();
HandlerThread handlerThread =
@@ -178,7 +178,7 @@
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mUserManager = UserManager.get(context);
- mUserServices = userServices;
+ mUserServices = new SparseArray<>();
Set<ComponentName> transportWhitelist =
SystemConfig.getInstance().getBackupTransportWhitelist();
mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
@@ -186,6 +186,9 @@
mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
UserHandle mainUser = getUserManager().getMainUser();
mDefaultBackupUserId = mainUser == null ? UserHandle.USER_SYSTEM : mainUser.getIdentifier();
+ if (DEBUG) {
+ Slog.d(TAG, "Default backup user id = " + mDefaultBackupUserId);
+ }
}
// TODO: Remove this when we implement DI by injecting in the construtor.
@@ -361,17 +364,6 @@
}
/**
- * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
- * Starts the backup service for this user if backup is active for this user. Offloads work onto
- * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
- * essential for device functioning.
- */
- @VisibleForTesting
- void onUnlockUser(int userId) {
- postToHandler(() -> startServiceForUser(userId));
- }
-
- /**
* Starts the backup service for user {@code userId} by creating a new instance of {@link
* UserBackupManagerService} and registering it with this service.
*/
@@ -1687,7 +1679,15 @@
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
- sInstance.onUnlockUser(user.getUserIdentifier());
+ // Starts the backup service for this user if backup is active for this user. Offloads
+ // work onto the handler thread {@link #mHandlerThread} to keep unlock time low since
+ // backup is not essential for device functioning.
+ sInstance.postToHandler(
+ () -> {
+ sInstance.updateDefaultBackupUserIdIfNeeded();
+ sInstance.startServiceForUser(user.getUserIdentifier());
+ sInstance.mHasFirstUserUnlockedSinceBoot = true;
+ });
}
@Override
@@ -1700,4 +1700,42 @@
publishBinderService(name, service);
}
}
+
+ /**
+ * On the first ever boot of a new device, the 'main' user might not exist for a short period of
+ * time and be created after {@link BackupManagerService} is created. In this case the {@link
+ * #mDefaultBackupUserId} will be the system user initially, but we need to change it to the
+ * newly created {@link UserManager#getMainUser()} later.
+ *
+ * <p>{@link Lifecycle#onUserUnlocking(SystemService.TargetUser)} (for any user) is the earliest
+ * point where we know that a main user (if there is going to be one) is created.
+ */
+ private void updateDefaultBackupUserIdIfNeeded() {
+ // The default user can only change before any user unlocks since boot, and it will only
+ // change from the system user to a non-system user.
+ if (mHasFirstUserUnlockedSinceBoot || mDefaultBackupUserId != UserHandle.USER_SYSTEM) {
+ return;
+ }
+
+ UserHandle mainUser = getUserManager().getMainUser();
+ if (mainUser == null) {
+ return;
+ }
+
+ if (mDefaultBackupUserId != mainUser.getIdentifier()) {
+ int oldDefaultBackupUserId = mDefaultBackupUserId;
+ mDefaultBackupUserId = mainUser.getIdentifier();
+ // We don't expect the service to be started for the old default user but we attempt to
+ // stop its service to be safe.
+ if (!isBackupActivatedForUser(oldDefaultBackupUserId)) {
+ stopServiceForUser(oldDefaultBackupUserId);
+ }
+ Slog.i(
+ TAG,
+ "Default backup user changed from "
+ + oldDefaultBackupUserId
+ + " to "
+ + mDefaultBackupUserId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 9d07365..2992bf9 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -81,6 +81,7 @@
import android.util.apk.ApkSigningBlockUtils;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.expresslog.Histogram;
import com.android.internal.os.IBinaryTransparencyService;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.pm.ApexManager;
@@ -141,6 +142,10 @@
private static final boolean DEBUG = false; // toggle this for local debug
+ private static final Histogram digestAllPackagesLatency = new Histogram(
+ "binary_transparency.value_digest_all_packages_latency_uniform",
+ new Histogram.UniformOptions(50, 0, 500));
+
private final Context mContext;
private String mVbmetaDigest;
// the system time (in ms) the last measurement was taken
@@ -350,8 +355,9 @@
writeAppInfoToLog(appInfo);
}
}
+ long timeSpentMeasuring = System.currentTimeMillis() - currentTimeMs;
+ digestAllPackagesLatency.logSample(timeSpentMeasuring);
if (DEBUG) {
- long timeSpentMeasuring = System.currentTimeMillis() - currentTimeMs;
Slog.d(TAG, "Measured " + packagesMeasured.size()
+ " packages altogether in " + timeSpentMeasuring + "ms");
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a66e598..57a0713 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -416,6 +416,11 @@
LinkCapacityEstimate.INVALID, LinkCapacityEstimate.INVALID)));
private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists;
+ private int[] mECBMReason;
+ private boolean[] mECBMStarted;
+ private int[] mSCBMReason;
+ private boolean[] mSCBMStarted;
+
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
* type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -556,7 +561,8 @@
return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
- || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
+ || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -707,7 +713,10 @@
mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
-
+ mECBMReason = copyOf(mECBMReason, mNumPhones);
+ mECBMStarted = copyOf(mECBMStarted, mNumPhones);
+ mSCBMReason = copyOf(mSCBMReason, mNumPhones);
+ mSCBMStarted = copyOf(mSCBMStarted, mNumPhones);
// ds -> ss switch.
if (mNumPhones < oldNumPhones) {
cutListToSize(mCellInfo, mNumPhones);
@@ -762,6 +771,10 @@
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
+ mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mECBMStarted[i] = false;
+ mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mSCBMStarted[i] = false;
}
}
}
@@ -831,6 +844,10 @@
mLinkCapacityEstimateLists = new ArrayList<>();
mCarrierPrivilegeStates = new ArrayList<>();
mCarrierServiceStates = new ArrayList<>();
+ mECBMReason = new int[numPhones];
+ mECBMStarted = new boolean[numPhones];
+ mSCBMReason = new int[numPhones];
+ mSCBMStarted = new boolean[numPhones];
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
@@ -870,6 +887,10 @@
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
+ mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mECBMStarted[i] = false;
+ mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mSCBMStarted[i] = false;
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -1441,6 +1462,31 @@
}
}
}
+ if (events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ boolean ecbmStarted = mECBMStarted[r.phoneId];
+ if (ecbmStarted) {
+ r.callback.onCallBackModeStarted(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL);
+ } else {
+ r.callback.onCallBackModeStopped(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL,
+ mECBMReason[r.phoneId]);
+ }
+
+ boolean scbmStarted = mSCBMStarted[r.phoneId];
+ if (scbmStarted) {
+ r.callback.onCallBackModeStarted(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS);
+ } else {
+ r.callback.onCallBackModeStopped(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS,
+ mSCBMReason[r.phoneId]);
+ }
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
}
@@ -3258,6 +3304,72 @@
}
}
+ @Override
+ public void notifyCallbackModeStarted(int phoneId, int subId, int type) {
+ if (!checkNotifyPermission("notifyCallbackModeStarted()")) {
+ return;
+ }
+ if (VDBG) {
+ log("notifyCallbackModeStarted: phoneId=" + phoneId + ", subId=" + subId
+ + ", type=" + type);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
+ mECBMStarted[phoneId] = true;
+ } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
+ mSCBMStarted[phoneId] = true;
+ }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ r.callback.onCallBackModeStarted(type);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+
+ @Override
+ public void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason) {
+ if (!checkNotifyPermission("notifyCallbackModeStopped()")) {
+ return;
+ }
+ if (VDBG) {
+ log("notifyCallbackModeStopped: phoneId=" + phoneId + ", subId=" + subId
+ + ", type=" + type + ", reason=" + reason);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
+ mECBMStarted[phoneId] = false;
+ mECBMReason[phoneId] = reason;
+ } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
+ mSCBMStarted[phoneId] = false;
+ mSCBMReason[phoneId] = reason;
+ }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ r.callback.onCallBackModeStopped(type, reason);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -3307,6 +3419,11 @@
pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i));
pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
+ pw.println("mECBMReason=" + mECBMReason[i]);
+ pw.println("mECBMStarted=" + mECBMStarted[i]);
+ pw.println("mSCBMReason=" + mSCBMReason[i]);
+ pw.println("mSCBMStarted=" + mSCBMStarted[i]);
+
// We need to obfuscate package names, and primitive arrays' native toString is ugly
Pair<List<String>, int[]> carrierPrivilegeState = mCarrierPrivilegeStates.get(i);
pw.println(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f0931ca..7da8869 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -102,6 +102,8 @@
import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
@@ -5581,6 +5583,25 @@
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
+ if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
+ boolean isChangeEnabled = CompatChanges.isChangeEnabled(
+ PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT,
+ owningUid);
+ logUnsafeMutableImplicitPi(packageName, resolvedTypes, owningUid, i, intent,
+ isChangeEnabled);
+ if (isChangeEnabled) {
+ String msg = packageName + ": Targeting U+ (version "
+ + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows"
+ + " creating or retrieving a PendingIntent with FLAG_MUTABLE,"
+ + " an implicit Intent within and without FLAG_NO_CREATE and"
+ + " FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for"
+ + " security reasons. To retrieve an already existing"
+ + " PendingIntent, use FLAG_NO_CREATE, however, to create a"
+ + " new PendingIntent with an implicit Intent use"
+ + " FLAG_IMMUTABLE.";
+ throw new IllegalArgumentException(msg);
+ }
+ }
intents[i] = new Intent(intent);
}
}
@@ -5633,6 +5654,24 @@
}
}
+ private void logUnsafeMutableImplicitPi(String packageName, String[] resolvedTypes,
+ int owningUid, int i, Intent intent, boolean isChangeEnabled) {
+ String[] categories = intent.getCategories() == null ? new String[0]
+ : intent.getCategories().toArray(String[]::new);
+ String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null
+ : resolvedTypes[i];
+ FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
+ UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED,
+ owningUid,
+ null,
+ packageName,
+ intent.getAction(),
+ categories,
+ resolvedType,
+ intent.getScheme(),
+ isChangeEnabled);
+ }
+
@Override
public int sendIntentSender(IApplicationThread caller, IIntentSender target,
IBinder allowlistToken, int code, Intent intent, String resolvedType,
@@ -12909,7 +12948,7 @@
callingUid);
String[] categories = intent.getCategories() == null ? new String[0]
: intent.getCategories().toArray(String[]::new);
- FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED,
+ FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
callingUid,
componentInfo,
@@ -14259,6 +14298,21 @@
// Ensure all internal loopers are registered for idle checks
BroadcastLoopers.addMyLooper();
+ if (Process.isSdkSandboxUid(realCallingUid)) {
+ final SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
+ SdkSandboxManagerLocal.class);
+ if (sdkSandboxManagerLocal == null) {
+ throw new IllegalStateException("SdkSandboxManagerLocal not found when sending"
+ + " a broadcast from an SDK sandbox uid.");
+ }
+ if (!sdkSandboxManagerLocal.canSendBroadcast(intent)) {
+ throw new SecurityException(
+ "Intent " + intent.getAction() + " may not be broadcast from an SDK sandbox"
+ + " uid. Given caller package " + callerPackage + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")");
+ }
+ }
+
if ((resultTo != null) && (resultToApp == null)) {
if (resultTo.asBinder() instanceof BinderProxy) {
// Warn when requesting results without a way to deliver them
@@ -14463,16 +14517,6 @@
}
}
- if (Process.isSdkSandboxUid(realCallingUid)) {
- SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
- SdkSandboxManagerLocal.class);
- if (sdkSandboxManagerLocal == null) {
- throw new IllegalStateException("SdkSandboxManagerLocal not found when sending"
- + " a broadcast from an SDK sandbox uid.");
- }
- sdkSandboxManagerLocal.enforceAllowedToSendBroadcast(intent);
- }
-
boolean timeoutExempt = false;
if (action != null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index dd49730..b5b86e0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4032,10 +4032,10 @@
vgs.adjustVolume(direction, flags);
}
- /** @see AudioManager#getLastAudibleVolumeGroupVolume(int) */
+ /** @see AudioManager#getLastAudibleVolumeForVolumeGroup(int) */
@android.annotation.EnforcePermission(android.Manifest.permission.QUERY_AUDIO_STATE)
- public int getLastAudibleVolumeGroupVolume(int groupId) {
- super.getLastAudibleVolumeGroupVolume_enforcePermission();
+ public int getLastAudibleVolumeForVolumeGroup(int groupId) {
+ super.getLastAudibleVolumeForVolumeGroup_enforcePermission();
synchronized (VolumeStreamState.class) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, ": no volume group found for id " + groupId);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 0a4b5b0..d26968a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -3236,10 +3236,7 @@
@Override
public boolean supportsFrameRateOverride() {
- return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true)
- && !SurfaceFlingerProperties.frame_rate_override_for_native_rates()
- .orElse(false)
- && SurfaceFlingerProperties.frame_rate_override_global().orElse(true);
+ return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true);
}
private DisplayManager getDisplayManager() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f5ca8aa..82e6e30 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1882,6 +1882,10 @@
? BrightnessEvent.FLAG_USER_SET : 0));
Slog.i(mTag, newEvent.toString(/* includeTime= */ false));
+ // Log all events which are not temporary
+ if (newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) {
+ logBrightnessEvent(newEvent, unthrottledBrightnessState);
+ }
if (userSetBrightnessChanged) {
logManualBrightnessEvent(newEvent);
}
@@ -2976,6 +2980,154 @@
}
}
+ // Return bucket index of range_[left]_[right] where
+ // left <= nits < right
+ private int nitsToRangeIndex(float nits) {
+ float[] boundaries = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80,
+ 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200,
+ 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000};
+ int[] rangeIndex = {
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_UNKNOWN,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_0_1,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1_2,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2_3,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3_4,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_4_5,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_5_6,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_6_7,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_7_8,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_8_9,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_9_10,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_10_20,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_20_30,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_30_40,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_40_50,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_50_60,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_60_70,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_70_80,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_80_90,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_90_100,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_100_200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_200_300,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_300_400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_400_500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_500_600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_600_700,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_700_800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_800_900,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_900_1000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1000_1200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1200_1400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1400_1600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1600_1800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1800_2000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2000_2250,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2250_2500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2500_2750,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2750_3000,
+ };
+ for (int i = 0; i < boundaries.length; i++) {
+ if (nits < boundaries[i]) {
+ return rangeIndex[i];
+ }
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3000_INF;
+ }
+
+ private int convertBrightnessReasonToStatsEnum(int brightnessReason) {
+ switch(brightnessReason) {
+ case BrightnessReason.REASON_UNKNOWN:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ case BrightnessReason.REASON_MANUAL:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_MANUAL;
+ case BrightnessReason.REASON_DOZE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE;
+ case BrightnessReason.REASON_DOZE_DEFAULT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE_DEFAULT;
+ case BrightnessReason.REASON_AUTOMATIC:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_AUTOMATIC;
+ case BrightnessReason.REASON_SCREEN_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF;
+ case BrightnessReason.REASON_OVERRIDE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_OVERRIDE;
+ case BrightnessReason.REASON_TEMPORARY:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_TEMPORARY;
+ case BrightnessReason.REASON_BOOST:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_BOOST;
+ case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR;
+ case BrightnessReason.REASON_FOLLOWER:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_FOLLOWER;
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ }
+
+ private int convertHbmModeToStatsEnum(int mode) {
+ switch(mode) {
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_HDR;
+ }
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ }
+
+ // unmodifiedBrightness: the brightness value that has not been
+ // modified by any modifiers(dimming/throttling/low-power-mode)
+ private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) {
+ int modifier = event.getReason().getModifier();
+ // It's easier to check if the brightness is at maximum level using the brightness
+ // value untouched by any modifiers
+ boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax();
+ float brightnessInNits = convertToNits(event.getBrightness());
+ float lowPowerModeFactor = event.getPowerFactor();
+ int rbcStrength = event.getRbcStrength();
+ float hbmMaxNits = convertToNits(event.getHbmMax());
+ float thermalCapNits = convertToNits(event.getThermalMax());
+
+ if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2,
+ event.getPhysicalDisplayId().hashCode(),
+ brightnessInNits,
+ convertToNits(unmodifiedBrightness),
+ nitsToRangeIndex(brightnessInNits),
+ brightnessIsMax,
+ (event.getFlags() & BrightnessEvent.FLAG_USER_SET) > 0,
+ convertBrightnessReasonToStatsEnum(event.getReason().getReason()),
+ convertHbmModeToStatsEnum(event.getHbmMode()),
+ (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0,
+ (modifier & BrightnessReason.MODIFIER_THROTTLED) > 0,
+ event.isRbcEnabled(),
+ event.getLux(),
+ event.wasShortTermModelActive(),
+ lowPowerModeFactor,
+ rbcStrength,
+ hbmMaxNits,
+ thermalCapNits,
+ event.isAutomaticBrightnessEnabled());
+ }
+ }
+
private void logManualBrightnessEvent(BrightnessEvent event) {
float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f;
int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 5667ddf..39bc09e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1595,6 +1595,10 @@
? BrightnessEvent.FLAG_USER_SET : 0));
Slog.i(mTag, newEvent.toString(/* includeTime= */ false));
+ // Log all events which are not temporary
+ if (newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) {
+ logBrightnessEvent(newEvent, unthrottledBrightnessState);
+ }
if (userSetBrightnessChanged) {
logManualBrightnessEvent(newEvent);
}
@@ -2512,6 +2516,154 @@
}
}
+ // Return bucket index of range_[left]_[right] where
+ // left <= nits < right
+ private int nitsToRangeIndex(float nits) {
+ float[] boundaries = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80,
+ 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200,
+ 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000};
+ int[] rangeIndex = {
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_UNKNOWN,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_0_1,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1_2,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2_3,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3_4,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_4_5,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_5_6,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_6_7,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_7_8,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_8_9,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_9_10,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_10_20,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_20_30,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_30_40,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_40_50,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_50_60,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_60_70,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_70_80,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_80_90,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_90_100,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_100_200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_200_300,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_300_400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_400_500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_500_600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_600_700,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_700_800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_800_900,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_900_1000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1000_1200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1200_1400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1400_1600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1600_1800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1800_2000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2000_2250,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2250_2500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2500_2750,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2750_3000,
+ };
+ for (int i = 0; i < boundaries.length; i++) {
+ if (nits < boundaries[i]) {
+ return rangeIndex[i];
+ }
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3000_INF;
+ }
+
+ private int convertBrightnessReasonToStatsEnum(int brightnessReason) {
+ switch(brightnessReason) {
+ case BrightnessReason.REASON_UNKNOWN:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ case BrightnessReason.REASON_MANUAL:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_MANUAL;
+ case BrightnessReason.REASON_DOZE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE;
+ case BrightnessReason.REASON_DOZE_DEFAULT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE_DEFAULT;
+ case BrightnessReason.REASON_AUTOMATIC:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_AUTOMATIC;
+ case BrightnessReason.REASON_SCREEN_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF;
+ case BrightnessReason.REASON_OVERRIDE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_OVERRIDE;
+ case BrightnessReason.REASON_TEMPORARY:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_TEMPORARY;
+ case BrightnessReason.REASON_BOOST:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_BOOST;
+ case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR;
+ case BrightnessReason.REASON_FOLLOWER:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_FOLLOWER;
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ }
+
+ private int convertHbmModeToStatsEnum(int mode) {
+ switch(mode) {
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_HDR;
+ }
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ }
+
+ // unmodifiedBrightness: the brightness value that has not been
+ // modified by any modifiers(dimming/throttling/low-power-mode)
+ private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) {
+ int modifier = event.getReason().getModifier();
+ // It's easier to check if the brightness is at maximum level using the brightness
+ // value untouched by any modifiers
+ boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax();
+ float brightnessInNits = convertToNits(event.getBrightness());
+ float lowPowerModeFactor = event.getPowerFactor();
+ int rbcStrength = event.getRbcStrength();
+ float hbmMaxNits = convertToNits(event.getHbmMax());
+ float thermalCapNits = convertToNits(event.getThermalMax());
+
+ if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2,
+ event.getPhysicalDisplayId().hashCode(),
+ brightnessInNits,
+ convertToNits(unmodifiedBrightness),
+ nitsToRangeIndex(brightnessInNits),
+ brightnessIsMax,
+ (event.getFlags() & BrightnessEvent.FLAG_USER_SET) > 0,
+ convertBrightnessReasonToStatsEnum(event.getReason().getReason()),
+ convertHbmModeToStatsEnum(event.getHbmMode()),
+ (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0,
+ (modifier & BrightnessReason.MODIFIER_THROTTLED) > 0,
+ event.isRbcEnabled(),
+ event.getLux(),
+ event.wasShortTermModelActive(),
+ lowPowerModeFactor,
+ rbcStrength,
+ hbmMaxNits,
+ thermalCapNits,
+ event.isAutomaticBrightnessEnabled());
+ }
+ }
+
private final class DisplayControllerHandler extends Handler {
DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 149a915..ce2656b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -103,7 +103,6 @@
import android.security.KeyStore;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
-import android.security.keystore.UserNotAuthenticatedException;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath;
@@ -788,31 +787,12 @@
}
}
- /**
- * Check if profile got unlocked but the keystore is still locked. This happens on full disk
- * encryption devices since the profile may not yet be running when we consider unlocking it
- * during the normal flow. In this case unlock the keystore for the profile.
- */
- private void ensureProfileKeystoreUnlocked(int userId) {
- final KeyStore ks = KeyStore.getInstance();
- if (ks.state(userId) == KeyStore.State.LOCKED
- && isCredentialSharableWithParent(userId)
- && hasUnifiedChallenge(userId)) {
- Slog.i(TAG, "Profile got unlocked, will unlock its keystore");
- // If boot took too long and the password in vold got expired, parent keystore will
- // be still locked, we ignore this case since the user will be prompted to unlock
- // the device after boot.
- unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
- }
- }
-
private void onUnlockUser(final int userId) {
// Perform tasks which require locks in LSS on a handler, as we are callbacks from
// ActivityManager.unlockUser()
mHandler.post(new Runnable() {
@Override
public void run() {
- ensureProfileKeystoreUnlocked(userId);
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
@@ -1335,7 +1315,7 @@
return credential;
}
- private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated) {
+ private void unlockChildProfile(int profileHandle) {
try {
doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
profileHandle, null /* progressCallback */, 0 /* flags */);
@@ -1345,8 +1325,6 @@
| BadPaddingException | CertificateException | IOException e) {
if (e instanceof FileNotFoundException) {
Slog.i(TAG, "Child profile key not found");
- } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
- Slog.i(TAG, "Parent keystore seems locked, ignoring");
} else {
Slog.e(TAG, "Failed to decrypt child profile key", e);
}
@@ -1410,7 +1388,7 @@
if (hasUnifiedChallenge(profile.id)) {
if (mUserManager.isUserRunning(profile.id)) {
// Unlock profile with unified lock
- unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */);
+ unlockChildProfile(profile.id);
} else {
try {
// Profile not ready for unlock yet, but decrypt the unified challenge now
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 27d2527..bba1dbe 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,6 +22,7 @@
import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static android.app.Notification.FLAG_INSISTENT;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_NO_DISMISS;
@@ -175,6 +176,7 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.LoggingOnly;
+import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -226,6 +228,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.VibrationEffect;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.notification.Adjustment;
@@ -528,6 +532,7 @@
private IPackageManager mPackageManager;
private PackageManager mPackageManagerClient;
PackageManagerInternal mPackageManagerInternal;
+ private PermissionManager mPermissionManager;
private PermissionPolicyInternal mPermissionPolicyInternal;
AudioManager mAudioManager;
AudioManagerInternal mAudioManagerInternal;
@@ -2226,7 +2231,8 @@
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
UsageStatsManagerInternal usageStatsManagerInternal,
TelecomManager telecomManager, NotificationChannelLogger channelLogger,
- SystemUiSystemPropertiesFlags.FlagResolver flagResolver) {
+ SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
+ PermissionManager permissionManager) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -2243,6 +2249,7 @@
mPackageManager = packageManager;
mPackageManagerClient = packageManagerClient;
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mPermissionManager = permissionManager;
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
mUmInternal = LocalServices.getService(UserManagerInternal.class);
mUsageStatsManagerInternal = usageStatsManagerInternal;
@@ -2557,7 +2564,8 @@
AppGlobals.getPermissionManager()),
LocalServices.getService(UsageStatsManagerInternal.class),
getContext().getSystemService(TelecomManager.class),
- new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver());
+ new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
+ getContext().getSystemService(PermissionManager.class));
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -6687,10 +6695,21 @@
handleSavePolicyFile();
}
+ private void makeStickyHun(Notification notification) {
+ notification.flags |= FLAG_FSI_REQUESTED_BUT_DENIED;
+ if (notification.contentIntent == null) {
+ // On notification click, if contentIntent is null, SystemUI launches the
+ // fullScreenIntent instead.
+ notification.contentIntent = notification.fullScreenIntent;
+ }
+ notification.fullScreenIntent = null;
+ }
+
@VisibleForTesting
protected void fixNotification(Notification notification, String pkg, String tag, int id,
@UserIdInt int userId, int notificationUid) throws NameNotFoundException,
RemoteException {
+
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
@@ -6728,13 +6747,40 @@
}
}
+ notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED;
+
if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
- int fullscreenIntentPermission = getContext().checkPermission(
- android.Manifest.permission.USE_FULL_SCREEN_INTENT, -1, notificationUid);
- if (fullscreenIntentPermission != PERMISSION_GRANTED) {
- notification.fullScreenIntent = null;
- Slog.w(TAG, "Package " + pkg +
- ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
+ final boolean forceDemoteFsiToStickyHun = mFlagResolver.isEnabled(
+ SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE);
+
+ final boolean showStickyHunIfDenied = mFlagResolver.isEnabled(
+ SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI);
+
+ if (forceDemoteFsiToStickyHun) {
+ makeStickyHun(notification);
+
+ } else if (showStickyHunIfDenied) {
+
+ final AttributionSource source = new AttributionSource.Builder(notificationUid)
+ .setPackageName(pkg)
+ .build();
+
+ final int permissionResult = mPermissionManager.checkPermissionForDataDelivery(
+ Manifest.permission.USE_FULL_SCREEN_INTENT, source, /* message= */ null);
+
+ if (permissionResult != PermissionCheckerManager.PERMISSION_GRANTED) {
+ makeStickyHun(notification);
+ }
+
+ } else {
+ int fullscreenIntentPermission = getContext().checkPermission(
+ android.Manifest.permission.USE_FULL_SCREEN_INTENT, -1, notificationUid);
+
+ if (fullscreenIntentPermission != PERMISSION_GRANTED) {
+ notification.fullScreenIntent = null;
+ Slog.w(TAG, "Package " + pkg + ": Use of fullScreenIntent requires the"
+ + "USE_FULL_SCREEN_INTENT permission");
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index b1c6f8c..2e86df8 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -485,18 +485,22 @@
String packageName, int userId) throws PackageManagerException {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null) {
- throw new PackageManagerException("Package " + packageName + " is unknown");
+ throw PackageManagerException.ofInternalError("Package " + packageName + " is unknown",
+ PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_PACKAGE_UNKNOWN);
} else if (!TextUtils.equals(volumeUuid, packageState.getVolumeUuid())) {
- throw new PackageManagerException(
+ throw PackageManagerException.ofInternalError(
"Package " + packageName + " found on unknown volume " + volumeUuid
- + "; expected volume " + packageState.getVolumeUuid());
+ + "; expected volume " + packageState.getVolumeUuid(),
+ PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_VOLUME_UNKNOWN);
} else if (!packageState.getUserStateOrDefault(userId).isInstalled()) {
- throw new PackageManagerException(
- "Package " + packageName + " not installed for user " + userId);
+ throw PackageManagerException.ofInternalError(
+ "Package " + packageName + " not installed for user " + userId,
+ PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_NOT_INSTALLED_FOR_USER);
} else if (packageState.getPkg() != null
&& !shouldHaveAppStorage(packageState.getPkg())) {
- throw new PackageManagerException(
- "Package " + packageName + " shouldn't have storage");
+ throw PackageManagerException.ofInternalError(
+ "Package " + packageName + " shouldn't have storage",
+ PackageManagerException.INTERNAL_ERROR_STORAGE_INVALID_SHOULD_NOT_HAVE_STORAGE);
}
}
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 1823a39..c1171fa 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -18,7 +18,6 @@
import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED;
import static android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
@@ -392,8 +391,7 @@
/** Returns whether the Safety Label Change notification, a privacy feature, is enabled. */
public static boolean isPrivacySafetyLabelChangeNotificationsEnabled() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false) && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, PERMISSION_RATIONALE_ENABLED, false);
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false);
}
@NonNull
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 9ec68da..cd70394 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -24,7 +24,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
@@ -1490,8 +1489,9 @@
synchronized (mPm.mLock) {
final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
if (ps == null) {
- request.setError(INSTALL_FAILED_INTERNAL_ERROR,
- "Missing settings for moved package " + pkgName);
+ request.setError(PackageManagerException.ofInternalError(
+ "Missing settings for moved package " + pkgName,
+ PackageManagerException.INTERNAL_ERROR_MISSING_SETTING_FOR_MOVE));
}
// We moved the entire application as-is, so bring over the
@@ -1523,8 +1523,9 @@
derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Error deriving application ABI: " + pme.getMessage());
+ throw PrepareFailure.ofInternalError(
+ "Error deriving application ABI: " + pme.getMessage(),
+ PackageManagerException.INTERNAL_ERROR_DERIVING_ABI);
}
}
@@ -1535,8 +1536,9 @@
setUpFsVerity(parsedPackage);
} catch (Installer.InstallerException | IOException | DigestException
| NoSuchAlgorithmException e) {
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to set up verity: " + e);
+ throw PrepareFailure.ofInternalError(
+ "Failed to set up verity: " + e,
+ PackageManagerException.INTERNAL_ERROR_VERITY_SETUP);
}
} else {
// Use the path returned by apexd
@@ -3215,8 +3217,9 @@
// uncompress the binary to its eventual destination on /data
final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
if (scanFile == null) {
- throw new PackageManagerException(
- "Unable to decompress stub at " + stubPkg.getPath());
+ throw PackageManagerException.ofInternalError(
+ "Unable to decompress stub at " + stubPkg.getPath(),
+ PackageManagerException.INTERNAL_ERROR_DECOMPRESS_STUB);
}
synchronized (mPm.mLock) {
mPm.mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
@@ -4174,10 +4177,12 @@
// This is relevant for cases where the disabled system package is used for flags or
// other metadata.
parsedPackage.hideAsFinal();
- throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+ throw PackageManagerException.ofInternalError(
+ "Package " + parsedPackage.getPackageName()
+ " at " + parsedPackage.getPath() + " ignored: updated version "
+ (pkgAlreadyExists ? String.valueOf(pkgSetting.getVersionCode()) : "unknown")
- + " better than this " + parsedPackage.getLongVersionCode());
+ + " better than this " + parsedPackage.getLongVersionCode(),
+ PackageManagerException.INTERNAL_ERROR_UPDATED_VERSION_BETTER_THAN_SYSTEM);
}
// Verify certificates against what was last scanned. Force re-collecting certificate in two
@@ -4449,8 +4454,9 @@
// but we still want the base name to be unique.
if ((scanFlags & SCAN_NEW_INSTALL) == 0
&& mPm.mPackages.containsKey(pkg.getManifestPackageName())) {
- throw new PackageManagerException(
- "Duplicate static shared lib provider package");
+ throw PackageManagerException.ofInternalError(
+ "Duplicate static shared lib provider package",
+ PackageManagerException.INTERNAL_ERROR_DUP_STATIC_SHARED_LIB_PROVIDER);
}
ScanPackageUtils.assertStaticSharedLibraryIsValid(pkg, scanFlags);
assertStaticSharedLibraryVersionCodeIsValid(pkg);
@@ -4543,8 +4549,9 @@
}
if (pkg.getLongVersionCode() < minVersionCode
|| pkg.getLongVersionCode() > maxVersionCode) {
- throw new PackageManagerException("Static shared"
- + " lib version codes must be ordered as lib versions");
+ throw PackageManagerException.ofInternalError("Static shared"
+ + " lib version codes must be ordered as lib versions",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_VERSION_CODES_ORDER);
}
}
@@ -4559,9 +4566,10 @@
// This must be an update to a system overlay. Immutable overlays cannot be
// upgraded.
if (!mPm.isOverlayMutable(pkg.getPackageName())) {
- throw new PackageManagerException("Overlay "
+ throw PackageManagerException.ofInternalError("Overlay "
+ pkg.getPackageName()
- + " is static and cannot be upgraded.");
+ + " is static and cannot be upgraded.",
+ PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC);
}
} else {
if ((scanFlags & SCAN_AS_VENDOR) != 0) {
@@ -4591,10 +4599,11 @@
}
if (!comparePackageSignatures(platformPkgSetting,
pkg.getSigningDetails().getSignatures())) {
- throw new PackageManagerException("Overlay "
+ throw PackageManagerException.ofInternalError("Overlay "
+ pkg.getPackageName()
+ " must target Q or later, "
- + "or be signed with the platform certificate");
+ + "or be signed with the platform certificate",
+ PackageManagerException.INTERNAL_ERROR_OVERLAY_LOW_TARGET_SDK);
}
}
@@ -4615,11 +4624,12 @@
pkg.getSigningDetails().getSignatures())) {
// check reference signature
if (mPm.mOverlayConfigSignaturePackage == null) {
- throw new PackageManagerException("Overlay "
+ throw PackageManagerException.ofInternalError("Overlay "
+ pkg.getPackageName() + " and target "
+ pkg.getOverlayTarget() + " signed with"
+ " different certificates, and the overlay lacks"
- + " <overlay android:targetName>");
+ + " <overlay android:targetName>",
+ PackageManagerException.INTERNAL_ERROR_OVERLAY_SIGNATURE1);
}
final PackageSetting refPkgSetting;
synchronized (mPm.mLock) {
@@ -4628,11 +4638,12 @@
}
if (!comparePackageSignatures(refPkgSetting,
pkg.getSigningDetails().getSignatures())) {
- throw new PackageManagerException("Overlay "
+ throw PackageManagerException.ofInternalError("Overlay "
+ pkg.getPackageName() + " signed with a different "
+ "certificate than both the reference package and "
+ "target " + pkg.getOverlayTarget() + ", and the "
- + "overlay lacks <overlay android:targetName>");
+ + "overlay lacks <overlay android:targetName>",
+ PackageManagerException.INTERNAL_ERROR_OVERLAY_SIGNATURE2);
}
}
}
@@ -4659,10 +4670,11 @@
}
if (!comparePackageSignatures(platformPkgSetting,
pkg.getSigningDetails().getSignatures())) {
- throw new PackageManagerException("Apps that share a user with a "
+ throw PackageManagerException.ofInternalError("Apps that share a user with a "
+ "privileged app must themselves be marked as privileged. "
+ pkg.getPackageName() + " shares privileged user "
- + pkg.getSharedUserId() + ".");
+ + pkg.getSharedUserId() + ".",
+ PackageManagerException.INTERNAL_ERROR_NOT_PRIV_SHARED_USER);
}
}
}
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 1516384..46ea010 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -93,6 +93,7 @@
@Nullable
private AndroidPackage mPkg;
private int mReturnCode;
+ private int mInternalErrorCode;
@Nullable
private String mReturnMsg;
// The set of packages consuming this shared library or null if no consumers exist.
@@ -227,6 +228,10 @@
return mReturnCode;
}
+ public int getInternalErrorCode() {
+ return mInternalErrorCode;
+ }
+
@Nullable
public IPackageInstallObserver2 getObserver() {
return mInstallArgs == null ? null : mInstallArgs.mObserver;
@@ -635,7 +640,12 @@
}
}
+ public void setError(PackageManagerException e) {
+ setError(null, e);
+ }
+
public void setError(String msg, PackageManagerException e) {
+ mInternalErrorCode = e.internalErrorCode;
mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index c3cc392..35862db 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -19,7 +19,6 @@
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING;
import static android.content.pm.PackageInstaller.SessionParams.USER_ACTION_UNSPECIFIED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -341,11 +340,15 @@
handle = NativeLibraryHelper.Handle.create(request.getCodeFile());
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
request.getAbiOverride(), isIncremental);
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ final String errorMessage = "Failed to copy native libraries";
+ request.setError(ret, errorMessage);
+ }
} catch (IOException e) {
final String errorMessage = "Copying native libraries failed";
Slog.e(TAG, errorMessage, e);
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- request.setError(ret, errorMessage);
+ request.setError(PackageManagerException.ofInternalError(errorMessage,
+ PackageManagerException.INTERNAL_ERROR_NATIVE_LIBRARY_COPY));
} finally {
IoUtils.closeQuietly(handle);
}
@@ -368,10 +371,10 @@
mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath);
} catch (Installer.InstallerException e) {
final String errorMessage = "Failed to move app";
- final int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- request.setError(ret, errorMessage);
+ request.setError(PackageManagerException.ofInternalError(errorMessage,
+ PackageManagerException.INTERNAL_ERROR_MOVE));
Slog.w(TAG, errorMessage, e);
- return ret;
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
}
@@ -594,13 +597,15 @@
final File dir = request.getOriginInfo().mResolvedFile;
final File[] apexes = dir.listFiles();
if (apexes == null) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- dir.getAbsolutePath() + " is not a directory");
+ throw PackageManagerException.ofInternalError(
+ dir.getAbsolutePath() + " is not a directory",
+ PackageManagerException.INTERNAL_ERROR_APEX_NOT_DIRECTORY);
}
if (apexes.length != 1) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ throw PackageManagerException.ofInternalError(
"Expected exactly one .apex file under " + dir.getAbsolutePath()
- + " got: " + apexes.length);
+ + " got: " + apexes.length,
+ PackageManagerException.INTERNAL_ERROR_APEX_MORE_THAN_ONE_FILE);
}
try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
ApexInfo apexInfo = mPm.mApexManager.installPackage(apexes[0]);
@@ -638,7 +643,8 @@
PackageManagerService pm)
throws PackageManagerException {
if (childInstallingSessions.size() == 0) {
- throw new PackageManagerException("No child sessions found!");
+ throw PackageManagerException.ofInternalError("No child sessions found!",
+ PackageManagerException.INTERNAL_ERROR_INSTALL_MISSING_CHILD_SESSIONS);
}
mPm = pm;
mUser = user;
diff --git a/services/core/java/com/android/server/pm/MultiPackageVerifyingSession.java b/services/core/java/com/android/server/pm/MultiPackageVerifyingSession.java
index 06e5497..126a930 100644
--- a/services/core/java/com/android/server/pm/MultiPackageVerifyingSession.java
+++ b/services/core/java/com/android/server/pm/MultiPackageVerifyingSession.java
@@ -47,7 +47,8 @@
throws PackageManagerException {
mUser = parent.getUser();
if (children.size() == 0) {
- throw new PackageManagerException("No child sessions found!");
+ throw PackageManagerException.ofInternalError("No child sessions found!",
+ PackageManagerException.INTERNAL_ERROR_VERIFY_MISSING_CHILD_SESSIONS);
}
mChildVerifyingSessions = children;
// Provide every child with reference to this object as parent
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 25f9ccd..fb6ae8b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -66,6 +66,8 @@
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -124,6 +126,7 @@
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
import android.os.SELinux;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IStorageHealthListener;
@@ -146,6 +149,7 @@
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
+import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -154,6 +158,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -297,8 +302,18 @@
private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
/**
+ * If an app being installed targets {@link Build.VERSION_CODES#S API 31} and above, the app
+ * can be installed without user action.
+ * See {@link PackageInstaller.SessionParams#setRequireUserAction} for other conditions required
+ * to be satisfied for a silent install.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long SILENT_INSTALL_ALLOWED = 265131695L;
+
+ /**
* The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
- * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#R} before getting the
+ * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#S} before getting the
* target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
* result will not trigger any user action in
* {@link #checkUserActionRequirement(PackageInstallerSession, IntentSender)}.
@@ -2353,13 +2368,7 @@
}
if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
- final int validatedTargetSdk;
- synchronized (session.mLock) {
- validatedTargetSdk = session.mValidatedTargetSdk;
- }
-
- if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION
- && validatedTargetSdk < Build.VERSION_CODES.R) {
+ if (!isTargetSdkConditionSatisfied(session)) {
session.sendPendingUserActionIntent(target);
return true;
}
@@ -2380,6 +2389,39 @@
return false;
}
+ /**
+ * Checks if the app being installed has a targetSdk more than the minimum required for a
+ * silent install. See {@link SessionParams#setRequireUserAction(int)} for details about the
+ * targetSdk requirement.
+ * @param session Current install session
+ * @return true if the targetSdk of the app being installed is more than the minimum required,
+ * resulting in a silent install, false otherwise.
+ */
+ private static boolean isTargetSdkConditionSatisfied(PackageInstallerSession session) {
+ final int validatedTargetSdk;
+ final String packageName;
+ synchronized (session.mLock) {
+ validatedTargetSdk = session.mValidatedTargetSdk;
+ packageName = session.mPackageName;
+ }
+
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = validatedTargetSdk;
+
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ try {
+ // Using manually constructed AppInfo to check if a change is enabled may not work
+ // in the future.
+ return validatedTargetSdk != INVALID_TARGET_SDK_VERSION
+ && platformCompat.isChangeEnabled(SILENT_INSTALL_ALLOWED, appInfo);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
+ return false;
+ }
+ }
+
private static @UserActionReason int userActionRequirementToReason(
@UserActionRequirement int requirement) {
switch (requirement) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index 4662389..dea6659 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,32 +16,138 @@
package com.android.server.pm;
+import android.annotation.IntDef;
import android.content.pm.PackageManager;
import com.android.server.pm.Installer.InstallerException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/** {@hide} */
public class PackageManagerException extends Exception {
- public final int error;
+ public static final int INTERNAL_ERROR_NATIVE_LIBRARY_COPY = -1;
+ public static final int INTERNAL_ERROR_MOVE = -2;
+ public static final int INTERNAL_ERROR_MISSING_SETTING_FOR_MOVE = -3;
+ public static final int INTERNAL_ERROR_DERIVING_ABI = -4;
+ public static final int INTERNAL_ERROR_VERITY_SETUP = -5;
+ public static final int INTERNAL_ERROR_SHARED_LIB_INSTALLED_TWICE = -6;
+ public static final int INTERNAL_ERROR_STORAGE_INVALID_PACKAGE_UNKNOWN = -7;
+ public static final int INTERNAL_ERROR_STORAGE_INVALID_VOLUME_UNKNOWN = -8;
+ public static final int INTERNAL_ERROR_STORAGE_INVALID_NOT_INSTALLED_FOR_USER = -9;
+ public static final int INTERNAL_ERROR_STORAGE_INVALID_SHOULD_NOT_HAVE_STORAGE = -10;
+ public static final int INTERNAL_ERROR_DECOMPRESS_STUB = -11;
+ public static final int INTERNAL_ERROR_UPDATED_VERSION_BETTER_THAN_SYSTEM = -12;
+ public static final int INTERNAL_ERROR_DUP_STATIC_SHARED_LIB_PROVIDER = -13;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_VERSION_CODES_ORDER = -14;
+ public static final int INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC = -15;
+ public static final int INTERNAL_ERROR_OVERLAY_LOW_TARGET_SDK = -16;
+ public static final int INTERNAL_ERROR_OVERLAY_SIGNATURE1 = -17;
+ public static final int INTERNAL_ERROR_OVERLAY_SIGNATURE2 = -18;
+ public static final int INTERNAL_ERROR_NOT_PRIV_SHARED_USER = -19;
+ public static final int INTERNAL_ERROR_INSTALL_MISSING_CHILD_SESSIONS = -20;
+ public static final int INTERNAL_ERROR_VERIFY_MISSING_CHILD_SESSIONS = -21;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_LOW_SDK = -22;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_INSTANT = -23;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_RENAMED = -24;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_DYNAMIC = -25;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_SHARED_USER = -26;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_ACTIVITY = -27;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_SERVICE = -28;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_CONTENT_PROVIDER = -29;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_BROADCAST_RECEIVER = -30;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION_GROUP = -31;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_FEATURE = -32;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION = -33;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_PROTECTED_BROADCAST = -34;
+ public static final int INTERNAL_ERROR_STATIC_SHARED_LIB_OVERLAY_TARGETS = -35;
+ public static final int INTERNAL_ERROR_APEX_NOT_DIRECTORY = -36;
+ public static final int INTERNAL_ERROR_APEX_MORE_THAN_ONE_FILE = -37;
- public PackageManagerException(String detailMessage) {
+ @IntDef(prefix = { "INTERNAL_ERROR_" }, value = {
+ INTERNAL_ERROR_NATIVE_LIBRARY_COPY,
+ INTERNAL_ERROR_MOVE,
+ INTERNAL_ERROR_MISSING_SETTING_FOR_MOVE,
+ INTERNAL_ERROR_DERIVING_ABI,
+ INTERNAL_ERROR_VERITY_SETUP,
+ INTERNAL_ERROR_SHARED_LIB_INSTALLED_TWICE,
+ INTERNAL_ERROR_STORAGE_INVALID_PACKAGE_UNKNOWN,
+ INTERNAL_ERROR_STORAGE_INVALID_VOLUME_UNKNOWN,
+ INTERNAL_ERROR_STORAGE_INVALID_NOT_INSTALLED_FOR_USER,
+ INTERNAL_ERROR_STORAGE_INVALID_SHOULD_NOT_HAVE_STORAGE,
+ INTERNAL_ERROR_DECOMPRESS_STUB,
+ INTERNAL_ERROR_UPDATED_VERSION_BETTER_THAN_SYSTEM,
+ INTERNAL_ERROR_DUP_STATIC_SHARED_LIB_PROVIDER,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_VERSION_CODES_ORDER,
+ INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC,
+ INTERNAL_ERROR_OVERLAY_LOW_TARGET_SDK,
+ INTERNAL_ERROR_OVERLAY_SIGNATURE1,
+ INTERNAL_ERROR_OVERLAY_SIGNATURE2,
+ INTERNAL_ERROR_NOT_PRIV_SHARED_USER,
+ INTERNAL_ERROR_INSTALL_MISSING_CHILD_SESSIONS,
+ INTERNAL_ERROR_VERIFY_MISSING_CHILD_SESSIONS,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_LOW_SDK,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_INSTANT,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_RENAMED,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_DYNAMIC,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_SHARED_USER,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_ACTIVITY,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_SERVICE,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_CONTENT_PROVIDER,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_BROADCAST_RECEIVER,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION_GROUP,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_FEATURE,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_PROTECTED_BROADCAST,
+ INTERNAL_ERROR_STATIC_SHARED_LIB_OVERLAY_TARGETS,
+ INTERNAL_ERROR_APEX_NOT_DIRECTORY,
+ INTERNAL_ERROR_APEX_MORE_THAN_ONE_FILE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InternalErrorCode {}
+
+ public final int error;
+ public final int internalErrorCode;
+
+ /**
+ * Default constructor without specifying the public return code of this exception.
+ * The public error code will be {@link PackageManager.INSTALL_FAILED_INTERNAL_ERROR}.
+ *
+ * Note for developers: if you use this constructor, assuming you have a different case where
+ * the exception should be thrown with {@link PackageManager.INSTALL_FAILED_INTERNAL_ERROR},
+ * please create a new {@link InternalErrorCode} constant.
+ *
+ * @param detailMessage Details about the cause of the exception.
+ * @param internalErrorCode Used for logging and analysis.
+ */
+ public static PackageManagerException ofInternalError(String detailMessage,
+ @InternalErrorCode int internalErrorCode) {
+ return new PackageManagerException(
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR, detailMessage, internalErrorCode);
+ }
+
+ protected PackageManagerException(int error, String detailMessage, int internalErrorCode) {
super(detailMessage);
- this.error = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ this.error = error;
+ this.internalErrorCode = internalErrorCode;
}
public PackageManagerException(int error, String detailMessage) {
super(detailMessage);
this.error = error;
+ this.internalErrorCode = 0;
}
public PackageManagerException(int error, String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
this.error = error;
+ this.internalErrorCode = 0;
}
public PackageManagerException(Throwable e) {
super(e);
this.error = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ this.internalErrorCode = 0;
}
public static PackageManagerException from(InstallerException e)
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 74bd0092a..93b0dcb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -972,6 +972,9 @@
showUid = true;
uid = Integer.parseInt(getNextArgRequired());
break;
+ case "--match-libraries":
+ getFlags |= PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;
+ break;
default:
pw.println("Error: Unknown option: " + opt);
return -1;
@@ -4080,6 +4083,7 @@
pw.println(" --factory-only: only show system packages excluding updates");
pw.println(" --uid UID: filter to only show packages with the given UID");
pw.println(" --user USER_ID: only list packages belonging to the given user");
+ pw.println(" --match-libraries: include packages that declare static shared and SDK libraries");
pw.println("");
pw.println(" list permission-groups");
pw.println(" Prints all known permission groups.");
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index c4ad20e..fe014a4 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -122,7 +122,7 @@
originalUsers /* original_user_ids */,
userManagerInternal.getUserTypesForStatsd(originalUsers) /* original_user_types */,
mInstallRequest.getReturnCode() /* public_return_code */,
- 0 /* internal_error_code */,
+ mInstallRequest.getInternalErrorCode() /* internal_error_code */,
apksSize /* apks_size_bytes */,
versionCode /* version_code */,
stepDurations.first /* install_steps */,
diff --git a/services/core/java/com/android/server/pm/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java
index a54ffa3..3180bac 100644
--- a/services/core/java/com/android/server/pm/PrepareFailure.java
+++ b/services/core/java/com/android/server/pm/PrepareFailure.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.content.pm.PackageManager;
import android.util.ExceptionUtils;
final class PrepareFailure extends PackageManagerException {
@@ -31,6 +32,15 @@
super(error, detailMessage);
}
+ public static PrepareFailure ofInternalError(String detailMessage, int internalErrorCode) {
+ return new PrepareFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, detailMessage,
+ internalErrorCode);
+ }
+
+ private PrepareFailure(int error, String message, int internalErrorCode) {
+ super(error, message, internalErrorCode);
+ }
+
PrepareFailure(String message, Exception e) {
super(((PackageManagerException) e).error,
ExceptionUtils.getCompleteMessage(message, e));
diff --git a/services/core/java/com/android/server/pm/ReconcileFailure.java b/services/core/java/com/android/server/pm/ReconcileFailure.java
index c9615ff..71a10f9 100644
--- a/services/core/java/com/android/server/pm/ReconcileFailure.java
+++ b/services/core/java/com/android/server/pm/ReconcileFailure.java
@@ -16,10 +16,18 @@
package com.android.server.pm;
+import android.content.pm.PackageManager;
+
final class ReconcileFailure extends PackageManagerException {
- ReconcileFailure(String message) {
- super("Reconcile failed: " + message);
+ public static ReconcileFailure ofInternalError(String message, int internalErrorCode) {
+ return new ReconcileFailure(message, internalErrorCode);
}
+
+ private ReconcileFailure(String message, int internalErrorCode) {
+ super(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "Reconcile failed: " + message,
+ internalErrorCode);
+ }
+
ReconcileFailure(int reason, String message) {
super(reason, "Reconcile failed: " + message);
}
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 58dcb02..d160740 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -82,8 +82,10 @@
for (SharedLibraryInfo info : allowedSharedLibInfos) {
if (!SharedLibraryUtils.addSharedLibraryToPackageVersionMap(
incomingSharedLibraries, info)) {
- throw new ReconcileFailure("Shared Library " + info.getName()
- + " is being installed twice in this set!");
+ throw ReconcileFailure.ofInternalError(
+ "Shared Library " + info.getName()
+ + " is being installed twice in this set!",
+ PackageManagerException.INTERNAL_ERROR_SHARED_LIB_INSTALLED_TWICE);
}
}
}
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index e4f3e2b..c3106a8 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -569,87 +569,101 @@
@PackageManagerService.ScanFlags int scanFlags) throws PackageManagerException {
// Static shared libraries should have at least O target SDK
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs must target O SDK or higher");
+ throw PackageManagerException.ofInternalError(
+ "Packages declaring static-shared libs must target O SDK or higher",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_LOW_SDK);
}
// Package declaring static a shared lib cannot be instant apps
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs cannot be instant apps");
+ throw PackageManagerException.ofInternalError(
+ "Packages declaring static-shared libs cannot be instant apps",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_INSTANT);
}
// Package declaring static a shared lib cannot be renamed since the package
// name is synthetic and apps can't code around package manager internals.
if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs cannot be renamed");
+ throw PackageManagerException.ofInternalError(
+ "Packages declaring static-shared libs cannot be renamed",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_RENAMED);
}
// Package declaring static a shared lib cannot declare dynamic libs
if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs cannot declare dynamic libs");
+ throw PackageManagerException.ofInternalError(
+ "Packages declaring static-shared libs cannot declare dynamic libs",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_DYNAMIC);
}
// Package declaring static a shared lib cannot declare shared users
if (pkg.getSharedUserId() != null) {
- throw new PackageManagerException(
- "Packages declaring static-shared libs cannot declare shared users");
+ throw PackageManagerException.ofInternalError(
+ "Packages declaring static-shared libs cannot declare shared users",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_SHARED_USER);
}
// Static shared libs cannot declare activities
if (!pkg.getActivities().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare activities");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare activities",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_ACTIVITY);
}
// Static shared libs cannot declare services
if (!pkg.getServices().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare services");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare services",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_SERVICE);
}
// Static shared libs cannot declare providers
if (!pkg.getProviders().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare content providers");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare content providers",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_CONTENT_PROVIDER);
}
// Static shared libs cannot declare receivers
if (!pkg.getReceivers().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare broadcast receivers");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare broadcast receivers",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_BROADCAST_RECEIVER);
}
// Static shared libs cannot declare permission groups
if (!pkg.getPermissionGroups().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare permission groups");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare permission groups",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION_GROUP);
}
// Static shared libs cannot declare attributions
if (!pkg.getAttributions().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare features");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare features",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_FEATURE);
}
// Static shared libs cannot declare permissions
if (!pkg.getPermissions().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare permissions");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare permissions",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PERMISSION);
}
// Static shared libs cannot declare protected broadcasts
if (!pkg.getProtectedBroadcasts().isEmpty()) {
- throw new PackageManagerException(
- "Static shared libs cannot declare protected broadcasts");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot declare protected broadcasts",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_PROTECTED_BROADCAST);
}
// Static shared libs cannot be overlay targets
if (pkg.getOverlayTarget() != null) {
- throw new PackageManagerException(
- "Static shared libs cannot be overlay targets");
+ throw PackageManagerException.ofInternalError(
+ "Static shared libs cannot be overlay targets",
+ PackageManagerException.INTERNAL_ERROR_STATIC_SHARED_LIB_OVERLAY_TARGETS);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a7fc3ed..19a0e03 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1962,6 +1962,14 @@
}
@Override
+ public int getDisplayIdAssignedToUser() {
+ // Not checking for any permission as it returns info about calling user
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
+ int displayId = mUserVisibilityMediator.getDisplayAssignedToUser(userId);
+ return displayId;
+ }
+
+ @Override
public @NonNull String getUserName() {
final int callingUid = Binder.getCallingUid();
if (!hasQueryOrCreateUsersPermission()
@@ -5920,11 +5928,21 @@
/* receiverPermission= */null);
}
+ /**
+ * @deprecated Use {@link
+ * android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead.
+ */
+ @Deprecated
@Override
public Bundle getApplicationRestrictions(String packageName) {
return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
}
+ /**
+ * @deprecated Use {@link
+ * android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} instead.
+ */
+ @Deprecated
@Override
public Bundle getApplicationRestrictionsForUser(String packageName, @UserIdInt int userId) {
if (UserHandle.getCallingUserId() != userId
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 89a9eb0..78761bd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -3305,7 +3305,7 @@
if (Objects.equals(packageName, PLATFORM_PACKAGE_NAME)) {
return true;
}
- if (!packageSetting.isPrivileged()) {
+ if (!(packageSetting.isSystem() && packageSetting.isPrivileged())) {
return true;
}
if (!mPrivilegedPermissionAllowlistSourcePackageNames
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index f248a02..b939cdc 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -19,6 +19,7 @@
import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
@@ -33,12 +34,15 @@
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.LowPowerStandbyAllowedReason;
import android.os.PowerManager.LowPowerStandbyPolicy;
+import android.os.PowerManager.LowPowerStandbyPortDescription;
import android.os.PowerManagerInternal;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -111,6 +115,7 @@
private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1;
private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2;
private static final int MSG_NOTIFY_POLICY_CHANGED = 3;
+ private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 4;
private static final String TAG_ROOT = "low-power-standby-policy";
private static final String TAG_IDENTIFIER = "identifier";
@@ -131,9 +136,11 @@
this::onStandbyTimeoutExpired;
private final LowPowerStandbyControllerInternal mLocalService = new LocalService();
private final SparseIntArray mUidAllowedReasons = new SparseIntArray();
+ private final List<StandbyPortsLock> mStandbyPortLocks = new ArrayList<>();
@GuardedBy("mLock")
private boolean mEnableCustomPolicy;
+ private boolean mEnableStandbyPorts;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -189,6 +196,49 @@
}
};
+ private final class StandbyPortsLock implements IBinder.DeathRecipient {
+ private final IBinder mToken;
+ private final int mUid;
+ private final List<LowPowerStandbyPortDescription> mPorts;
+
+ StandbyPortsLock(IBinder token, int uid, List<LowPowerStandbyPortDescription> ports) {
+ mToken = token;
+ mUid = uid;
+ mPorts = ports;
+ }
+
+ public boolean linkToDeath() {
+ try {
+ mToken.linkToDeath(this, 0);
+ return true;
+ } catch (RemoteException e) {
+ Slog.i(TAG, "StandbyPorts token already died");
+ return false;
+ }
+ }
+
+ public void unlinkToDeath() {
+ mToken.unlinkToDeath(this, 0);
+ }
+
+ public IBinder getToken() {
+ return mToken;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public List<LowPowerStandbyPortDescription> getPorts() {
+ return mPorts;
+ }
+
+ @Override
+ public void binderDied() {
+ releaseStandbyPorts(mToken);
+ }
+ }
+
@GuardedBy("mLock")
private AlarmManager mAlarmManager;
@GuardedBy("mLock")
@@ -311,6 +361,7 @@
mDeviceConfig.registerPropertyUpdateListener(mContext.getMainExecutor(),
properties -> onDeviceConfigFlagsChanged());
mEnableCustomPolicy = mDeviceConfig.enableCustomPolicy();
+ mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts();
if (mEnableCustomPolicy) {
mPolicy = loadPolicy();
@@ -336,6 +387,8 @@
enqueueNotifyAllowlistChangedLocked();
mEnableCustomPolicy = enableCustomPolicy;
}
+
+ mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts();
}
}
@@ -861,6 +914,78 @@
}
}
+ private int findIndexOfStandbyPorts(@NonNull IBinder token) {
+ for (int i = 0; i < mStandbyPortLocks.size(); i++) {
+ if (mStandbyPortLocks.get(i).getToken() == token) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ void acquireStandbyPorts(@NonNull IBinder token, int uid,
+ @NonNull List<LowPowerStandbyPortDescription> ports) {
+ validatePorts(ports);
+
+ StandbyPortsLock standbyPortsLock = new StandbyPortsLock(token, uid, ports);
+ synchronized (mLock) {
+ if (findIndexOfStandbyPorts(token) != -1) {
+ return;
+ }
+
+ if (standbyPortsLock.linkToDeath()) {
+ mStandbyPortLocks.add(standbyPortsLock);
+ if (mEnableStandbyPorts && isEnabled() && isPackageExempt(uid)) {
+ enqueueNotifyStandbyPortsChangedLocked();
+ }
+ }
+ }
+ }
+
+ void validatePorts(@NonNull List<LowPowerStandbyPortDescription> ports) {
+ for (LowPowerStandbyPortDescription portDescription : ports) {
+ int port = portDescription.getPortNumber();
+ if (port < 0 || port > 0xFFFF) {
+ throw new IllegalArgumentException("port out of range:" + port);
+ }
+ }
+ }
+
+ void releaseStandbyPorts(@NonNull IBinder token) {
+ synchronized (mLock) {
+ int index = findIndexOfStandbyPorts(token);
+ if (index == -1) {
+ return;
+ }
+
+ StandbyPortsLock standbyPortsLock = mStandbyPortLocks.remove(index);
+ standbyPortsLock.unlinkToDeath();
+ if (mEnableStandbyPorts && isEnabled() && isPackageExempt(standbyPortsLock.getUid())) {
+ enqueueNotifyStandbyPortsChangedLocked();
+ }
+ }
+ }
+
+ @NonNull
+ List<LowPowerStandbyPortDescription> getActiveStandbyPorts() {
+ List<LowPowerStandbyPortDescription> activeStandbyPorts = new ArrayList<>();
+ synchronized (mLock) {
+ if (!isEnabled() || !mEnableStandbyPorts) {
+ return activeStandbyPorts;
+ }
+
+ List<Integer> exemptPackageAppIds = getExemptPackageAppIdsLocked();
+ for (StandbyPortsLock standbyPortsLock : mStandbyPortLocks) {
+ int standbyPortsAppid = UserHandle.getAppId(standbyPortsLock.getUid());
+ if (exemptPackageAppIds.contains(standbyPortsAppid)) {
+ activeStandbyPorts.addAll(standbyPortsLock.getPorts());
+ }
+ }
+
+ return activeStandbyPorts;
+ }
+ }
+
private boolean policyChangeAffectsAllowlistLocked(
@Nullable LowPowerStandbyPolicy oldPolicy, @Nullable LowPowerStandbyPolicy newPolicy) {
final LowPowerStandbyPolicy policyA = policyOrDefault(oldPolicy);
@@ -941,6 +1066,17 @@
}
}
ipw.decreaseIndent();
+
+ final List<LowPowerStandbyPortDescription> activeStandbyPorts = getActiveStandbyPorts();
+ if (!activeStandbyPorts.isEmpty()) {
+ ipw.println();
+ ipw.println("Active standby ports locks:");
+ ipw.increaseIndent();
+ for (LowPowerStandbyPortDescription portDescription : activeStandbyPorts) {
+ ipw.print(portDescription.toString());
+ }
+ ipw.decreaseIndent();
+ }
}
ipw.decreaseIndent();
}
@@ -1006,6 +1142,9 @@
case MSG_NOTIFY_POLICY_CHANGED:
notifyPolicyChanged((LowPowerStandbyPolicy) msg.obj);
break;
+ case MSG_NOTIFY_STANDBY_PORTS_CHANGED:
+ notifyStandbyPortsChanged();
+ break;
}
}
}
@@ -1172,6 +1311,29 @@
npmi.setLowPowerStandbyAllowlist(allowlistUids);
}
+ @GuardedBy("mLock")
+ private void enqueueNotifyStandbyPortsChangedLocked() {
+ final long now = mClock.elapsedRealtime();
+
+ if (DEBUG) {
+ Slog.d(TAG, "enqueueNotifyStandbyPortsChangedLocked");
+ }
+
+ final Message msg = mHandler.obtainMessage(MSG_NOTIFY_STANDBY_PORTS_CHANGED);
+ mHandler.sendMessageAtTime(msg, now);
+ }
+
+ private void notifyStandbyPortsChanged() {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyStandbyPortsChanged");
+ }
+
+ final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ Manifest.permission.MANAGE_LOW_POWER_STANDBY);
+ }
+
/**
* Class that is used to read device config for low power standby configuration.
*/
@@ -1179,6 +1341,7 @@
public static class DeviceConfigWrapper {
public static final String NAMESPACE = "low_power_standby";
public static final String FEATURE_FLAG_ENABLE_POLICY = "enable_policy";
+ public static final String FEATURE_FLAG_ENABLE_STANDBY_PORTS = "enable_standby_ports";
/**
* Returns true if custom policies are enabled.
@@ -1189,6 +1352,14 @@
}
/**
+ * Returns true if standby ports are enabled.
+ * Otherwise, returns false, and {@link #getActiveStandbyPorts()} will always be empty.
+ */
+ public boolean enableStandbyPorts() {
+ return DeviceConfig.getBoolean(NAMESPACE, FEATURE_FLAG_ENABLE_STANDBY_PORTS, false);
+ }
+
+ /**
* Registers a DeviceConfig update listener.
*/
public void registerPropertyUpdateListener(
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ddf70f3..b83d509 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -6226,6 +6226,61 @@
}
}
+ @Override // Binder call
+ @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)
+ public void acquireLowPowerStandbyPorts(IBinder token,
+ List<LowPowerStandbyPortDescription> ports) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS,
+ "acquireLowPowerStandbyPorts");
+
+ final int callingUid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mLowPowerStandbyController.acquireStandbyPorts(token, callingUid,
+ PowerManager.LowPowerStandbyPortDescription.fromParcelable(ports));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS)
+ public void releaseLowPowerStandbyPorts(IBinder token) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS,
+ "releaseLowPowerStandbyPorts");
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mLowPowerStandbyController.releaseStandbyPorts(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_LOW_POWER_STANDBY,
+ android.Manifest.permission.DEVICE_POWER
+ })
+ public List<LowPowerStandbyPortDescription> getActiveLowPowerStandbyPorts() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
+ != PackageManager.PERMISSION_GRANTED) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_LOW_POWER_STANDBY,
+ "getActiveLowPowerStandbyPorts");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return PowerManager.LowPowerStandbyPortDescription.toParcelable(
+ mLowPowerStandbyController.getActiveStandbyPorts());
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
/**
* Gets the reason for the last time the phone had to reboot.
*
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index e3d2189..43f96e7 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -505,47 +505,9 @@
return mTemperatureWatcher.getForecast(forecastSeconds);
}
- private void dumpItemsLocked(PrintWriter pw, String prefix,
- Collection<?> items) {
- for (Iterator iterator = items.iterator(); iterator.hasNext();) {
- pw.println(prefix + iterator.next().toString());
- }
- }
-
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- pw.println("IsStatusOverride: " + mIsStatusOverride);
- pw.println("ThermalEventListeners:");
- mThermalEventListeners.dump(pw, "\t");
- pw.println("ThermalStatusListeners:");
- mThermalStatusListeners.dump(pw, "\t");
- pw.println("Thermal Status: " + mStatus);
- pw.println("Cached temperatures:");
- dumpItemsLocked(pw, "\t", mTemperatureMap.values());
- pw.println("HAL Ready: " + mHalReady.get());
- if (mHalReady.get()) {
- pw.println("HAL connection:");
- mHalWrapper.dump(pw, "\t");
- pw.println("Current temperatures from HAL:");
- dumpItemsLocked(pw, "\t",
- mHalWrapper.getCurrentTemperatures(false, 0));
- pw.println("Current cooling devices from HAL:");
- dumpItemsLocked(pw, "\t",
- mHalWrapper.getCurrentCoolingDevices(false, 0));
- pw.println("Temperature static thresholds from HAL:");
- dumpItemsLocked(pw, "\t",
- mHalWrapper.getTemperatureThresholds(false, 0));
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ dumpInternal(fd, pw, args);
}
private boolean isCallerShell() {
@@ -567,6 +529,62 @@
};
+ private static void dumpItemsLocked(PrintWriter pw, String prefix,
+ Collection<?> items) {
+ for (Iterator iterator = items.iterator(); iterator.hasNext();) {
+ pw.println(prefix + iterator.next().toString());
+ }
+ }
+
+ private static void dumpTemperatureThresholds(PrintWriter pw, String prefix,
+ List<TemperatureThreshold> thresholds) {
+ for (TemperatureThreshold threshold : thresholds) {
+ pw.println(prefix + "TemperatureThreshold{mType=" + threshold.type
+ + ", mName=" + threshold.name
+ + ", mHotThrottlingThresholds=" + Arrays.toString(
+ threshold.hotThrottlingThresholds)
+ + ", mColdThrottlingThresholds=" + Arrays.toString(
+ threshold.coldThrottlingThresholds)
+ + "}");
+ }
+ }
+
+ @VisibleForTesting
+ void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ pw.println("IsStatusOverride: " + mIsStatusOverride);
+ pw.println("ThermalEventListeners:");
+ mThermalEventListeners.dump(pw, "\t");
+ pw.println("ThermalStatusListeners:");
+ mThermalStatusListeners.dump(pw, "\t");
+ pw.println("Thermal Status: " + mStatus);
+ pw.println("Cached temperatures:");
+ dumpItemsLocked(pw, "\t", mTemperatureMap.values());
+ pw.println("HAL Ready: " + mHalReady.get());
+ if (mHalReady.get()) {
+ pw.println("HAL connection:");
+ mHalWrapper.dump(pw, "\t");
+ pw.println("Current temperatures from HAL:");
+ dumpItemsLocked(pw, "\t",
+ mHalWrapper.getCurrentTemperatures(false, 0));
+ pw.println("Current cooling devices from HAL:");
+ dumpItemsLocked(pw, "\t",
+ mHalWrapper.getCurrentCoolingDevices(false, 0));
+ pw.println("Temperature static thresholds from HAL:");
+ dumpTemperatureThresholds(pw, "\t",
+ mHalWrapper.getTemperatureThresholds(false, 0));
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
class ThermalShellCommand extends ShellCommand {
@Override
public int onCommand(String cmd) {
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index b04d7df..8e8abf6 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -452,6 +452,11 @@
}
@Override
+ public void onLanguageDetection(Bundle results) throws RemoteException {
+ mRemoteListener.onLanguageDetection(results);
+ }
+
+ @Override
public void onEvent(int eventType, Bundle params) throws RemoteException {
mRemoteListener.onEvent(eventType, params);
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index f452378..587138d 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -45,6 +45,7 @@
import android.util.DebugUtils;
import android.util.Slog;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
import java.lang.annotation.Retention;
@@ -176,22 +177,24 @@
if (callingUid == Process.ROOT_UID
|| callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
- return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
- BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
+ callingUid, realCallingUid, intent, "Important callingUid");
}
// Always allow home application to start activities.
if (isHomeApp(callingUid, callingPackage)) {
- return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
- BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "Home app");
}
// IME should always be allowed to start activity, like IME settings.
final WindowState imeWindow =
mService.mRootWindowContainer.getCurrentInputMethodWindow();
if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
- return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
- BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "Active ime");
}
}
@@ -218,8 +221,8 @@
&& callingUidHasAnyVisibleWindow)
|| isCallingUidPersistentSystemProcess;
if (useCallingUidState && allowCallingUidStartActivity) {
- return logStartAllowedAndReturnCode(/*background*/ false,
- BAL_ALLOW_VISIBLE_WINDOW,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW,
+ /*background*/ false, callingUid, realCallingUid, intent,
"callingUidHasAnyVisibleWindow = "
+ callingUid
+ ", isCallingUidPersistentSystemProcess = "
@@ -254,8 +257,8 @@
Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
- return logStartAllowedAndReturnCode(/*background*/ false, realCallingUid,
- BAL_ALLOW_SDK_SANDBOX,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
+ /*background*/ false, callingUid, realCallingUid, intent,
"uid in SDK sandbox has visible (non-toast) window");
}
}
@@ -276,16 +279,16 @@
-1,
true)
== PackageManager.PERMISSION_GRANTED) {
- return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
- BAL_ALLOW_PENDING_INTENT,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
}
// don't abort if the realCallingUid has a visible window
// TODO(b/171459802): We should check appSwitchAllowed also
if (realCallingUidHasAnyVisibleWindow) {
- return logStartAllowedAndReturnCode(/*background*/ false,
- callingUid, BAL_ALLOW_PENDING_INTENT,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid has visible (non-toast) window. realCallingUid: "
+ realCallingUid);
}
@@ -293,9 +296,8 @@
// wasn't allowed to start an activity
if (isRealCallingUidPersistentSystemProcess
&& backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
- return logStartAllowedAndReturnCode(/*background*/ false,
- callingUid,
- BAL_ALLOW_PENDING_INTENT,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
"realCallingUid is persistent system process AND intent "
+ "sender allowed (allowBackgroundActivityStart = true). "
+ "realCallingUid: " + realCallingUid);
@@ -303,8 +305,9 @@
// don't abort if the realCallingUid is an associated companion app
if (mService.isAssociatedCompanionApp(
UserHandle.getUserId(realCallingUid), realCallingUid)) {
- return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
- BAL_ALLOW_PENDING_INTENT, "realCallingUid is a companion app. "
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "realCallingUid is a companion app. "
+ "realCallingUid: " + realCallingUid);
}
}
@@ -312,25 +315,28 @@
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
callingPid, callingUid) == PERMISSION_GRANTED) {
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_PERMISSION,
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
+ /*background*/ true, callingUid, realCallingUid, intent,
"START_ACTIVITIES_FROM_BACKGROUND permission granted");
}
// don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Recents Component");
}
// don't abort if the callingUid is the device owner
if (mService.isDeviceOwner(callingUid)) {
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Device Owner");
}
// don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Companion App");
}
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
@@ -339,8 +345,9 @@
"Background activity start for "
+ callingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_SAW_PERMISSION, "SYSTEM_ALERT_WINDOW permission is granted");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "SYSTEM_ALERT_WINDOW permission is granted");
}
// don't abort if the callingUid and callingPackage have the
// OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
@@ -349,9 +356,9 @@
callingUid,
callingPackage)
== AppOpsManager.MODE_ALLOWED) {
- return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
- BAL_ALLOW_PERMISSION,
- "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
+ /*background*/ true, callingUid, realCallingUid, intent,
+ "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
}
}
// If we don't have callerApp at this point, no caller was provided to startActivity().
@@ -369,7 +376,8 @@
@BalCode int balAllowedForCaller = callerApp
.areBackgroundActivityStartsAllowed(appSwitchState);
if (balAllowedForCaller != BAL_BLOCK) {
- return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForCaller,
+ return logStartAllowedAndReturnCode(balAllowedForCaller,
+ /*background*/ true, callingUid, realCallingUid, intent,
"callerApp process (pid = " + callerApp.getPid()
+ ", uid = " + callerAppUid + ") is allowed");
}
@@ -382,7 +390,8 @@
int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
if (proc != callerApp
&& balAllowedForUid != BAL_BLOCK) {
- return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForUid,
+ return logStartAllowedAndReturnCode(balAllowedForUid,
+ /*background*/ true, callingUid, realCallingUid, intent,
"process" + proc.getPid()
+ " from uid " + callerAppUid + " is allowed");
}
@@ -448,27 +457,21 @@
return BAL_BLOCK;
}
- private int logStartAllowedAndReturnCode(boolean background, int callingUid, int code,
- String msg) {
- if (DEBUG_ACTIVITY_STARTS) {
- return logStartAllowedAndReturnCode(background, code,
- msg, "callingUid: " + callingUid);
- }
- return code;
+ static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
+ int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
+ return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
+ DEBUG_ACTIVITY_STARTS ? ("[Process(" + pid + ")]" + msg) : "");
}
- private int logStartAllowedAndReturnCode(boolean background, int code,
- String... msg) {
+ static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
+ int callingUid, int realCallingUid, Intent intent, String msg) {
+ statsLogBalAllowed(code, callingUid, realCallingUid, intent);
if (DEBUG_ACTIVITY_STARTS) {
StringBuilder builder = new StringBuilder();
if (background) {
builder.append("Background ");
}
- builder.append("Activity start allowed: ");
- for (int i = 0; i < msg.length; i++) {
- builder.append(msg[i]);
- builder.append(". ");
- }
+ builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
builder.append("BAL Code: ");
builder.append(code);
Slog.d(TAG, builder.toString());
@@ -482,4 +485,27 @@
/* name= */ "system_exempt_from_activity_bg_start_restriction_enabled",
/* defaultValue= */ true);
}
+
+ private static void statsLogBalAllowed(
+ @BalCode int code, int callingUid, int realCallingUid, Intent intent) {
+ if (code == BAL_ALLOW_PENDING_INTENT
+ && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) {
+ String activityName =
+ intent != null ? intent.getComponent().flattenToShortString() : "";
+ FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+ activityName,
+ code,
+ callingUid,
+ realCallingUid);
+ }
+ if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND
+ || code == BAL_ALLOW_SAW_PERMISSION) {
+ // We don't need to know which activity in this case.
+ FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+ /*activityName*/ "",
+ code,
+ callingUid,
+ realCallingUid);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 9298afc..74f0ddc 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -104,37 +104,29 @@
long lastActivityFinishTime) {
// Allow if the proc is instrumenting with background activity starts privs.
if (hasBackgroundActivityStartPrivileges) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process instrumenting with background "
+ return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+ BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ pid, "Activity start allowed: process instrumenting with background "
+ "activity starts privileges");
- }
- return BAL_ALLOW_PERMISSION;
}
// Allow if the flag was explicitly set.
if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process allowed by token");
- }
- return BAL_ALLOW_PERMISSION;
+ return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+ BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+ pid, "Activity start allowed: process allowed by token");
}
// Allow if the caller is bound by a UID that's currently foreground.
if (isBoundByForegroundUid()) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process bound by foreground uid");
- }
- return BAL_ALLOW_VISIBLE_WINDOW;
+ return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+ BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, uid, uid, /*intent*/ null,
+ pid, "Activity start allowed: process bound by foreground uid");
}
// Allow if the caller has an activity in any foreground task.
if (hasActivityInVisibleTask
&& (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process has activity in foreground task");
- }
- return BAL_ALLOW_FOREGROUND;
+ return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+ BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+ pid, "Activity start allowed: process has activity in foreground task");
}
// If app switching is not allowed, we ignore all the start activity grace period
@@ -149,12 +141,10 @@
// let app to be able to start background activity even it's in grace period.
if (lastActivityLaunchTime > lastStopAppSwitchesTime
|| lastActivityFinishTime > lastStopAppSwitchesTime) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: within "
- + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
- }
- return BAL_ALLOW_GRACE_PERIOD;
+ return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+ BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null,
+ pid, "Activity start allowed: within "
+ + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
}
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0e61b46..8cd22fe 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5658,8 +5658,8 @@
final Rect df = state.getDisplayFrame();
final Insets gestureInsets = state.calculateInsets(df, systemGestures(),
false /* ignoreVisibility */);
- mSystemGestureFrameLeft.set(df.left, df.top, gestureInsets.left, df.bottom);
- mSystemGestureFrameRight.set(gestureInsets.right, df.top, df.right, df.bottom);
+ mSystemGestureFrameLeft.set(df.left, df.top, df.left + gestureInsets.left, df.bottom);
+ mSystemGestureFrameRight.set(df.right - gestureInsets.right, df.top, df.right, df.bottom);
final Region touchableRegion = Region.obtain();
final Region local = Region.obtain();
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index cbc36c3..5a481f4 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1000,7 +1000,7 @@
@VisibleForTesting
boolean shouldShowLetterboxUi(WindowState mainWindow) {
- return isSurfaceReadyAndVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed()
+ return isSurfaceVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed()
// Check for FLAG_SHOW_WALLPAPER explicitly instead of using
// WindowContainer#showWallpaper because the later will return true when this
// activity is using blurred wallpaper for letterbox background.
@@ -1008,11 +1008,8 @@
}
@VisibleForTesting
- boolean isSurfaceReadyAndVisible(WindowState mainWindow) {
- boolean surfaceReady = mainWindow.isDrawn() // Regular case
- // Waiting for relayoutWindow to call preserveSurface
- || mainWindow.isDragResizeChanged();
- return surfaceReady && (mActivityRecord.isVisible()
+ boolean isSurfaceVisible(WindowState mainWindow) {
+ return mainWindow.isOnScreen() && (mActivityRecord.isVisible()
|| mActivityRecord.isVisibleRequested());
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 88b82d7..e16b0f7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -175,6 +175,8 @@
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
+ private static final String TAG_DIALER_PACKAGE = "dialer_package";
+ private static final String TAG_SMS_PACKAGE = "sms_package";
// If the ActiveAdmin is a permission-based admin, then info will be null because the
// permission-based admin is not mapped to a device administrator component.
@@ -350,6 +352,8 @@
boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
int mWifiMinimumSecurityLevel = DevicePolicyManager.WIFI_SECURITY_OPEN;
+ String mDialerPackage;
+ String mSmsPackage;
ActiveAdmin(DeviceAdminInfo info, boolean isParent) {
this.info = info;
@@ -661,6 +665,12 @@
mManagedSubscriptionsPolicy.saveToXml(out);
out.endTag(null, TAG_MANAGED_SUBSCRIPTIONS_POLICY);
}
+ if (!TextUtils.isEmpty(mDialerPackage)) {
+ writeAttributeValueToXml(out, TAG_DIALER_PACKAGE, mDialerPackage);
+ }
+ if (!TextUtils.isEmpty(mSmsPackage)) {
+ writeAttributeValueToXml(out, TAG_SMS_PACKAGE, mSmsPackage);
+ }
}
private void writePackagePolicy(TypedXmlSerializer out, String tag,
@@ -969,6 +979,10 @@
mManagedSubscriptionsPolicy = ManagedSubscriptionsPolicy.readFromXml(parser);
} else if (TAG_CREDENTIAL_MANAGER_POLICY.equals(tag)) {
mCredentialManagerPolicy = readPackagePolicy(parser);
+ } else if (TAG_DIALER_PACKAGE.equals(tag)) {
+ mDialerPackage = parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_SMS_PACKAGE.equals(tag)) {
+ mSmsPackage = parser.getAttributeValue(null, ATTR_VALUE);
} else {
Slogf.w(LOG_TAG, "Unknown admin tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
@@ -1449,5 +1463,10 @@
pw.println(mManagedSubscriptionsPolicy);
pw.decreaseIndent();
}
+
+ pw.print("mDialerPackage=");
+ pw.println(mDialerPackage);
+ pw.print("mSmsPackage=");
+ pw.println(mSmsPackage);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b386598..729a482 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,24 +19,63 @@
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
import static android.Manifest.permission.LOCK_DEVICE;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUTOFILL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_BLUETOOTH;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CALLS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_DISPLAY;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_FUN;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_KEYGUARD;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCALE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCATION;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_LOCK_TASK;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MICROPHONE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_MTE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PRINTING;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SMS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_STATUS_BAR;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USERS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_VPN;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WALLPAPER;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WINDOWS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
@@ -47,11 +86,10 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
-import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
-import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
+import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
@@ -78,11 +116,10 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
-import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_APP_STANDBY;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
-import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_HIBERNATION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_POWER_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_SUSPENSION;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -342,6 +379,7 @@
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -482,8 +520,12 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -748,7 +790,7 @@
new ArrayMap<>();
static {
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
- EXEMPT_FROM_APP_STANDBY, OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY);
+ EXEMPT_FROM_SUSPENSION, OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION);
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS);
@@ -758,9 +800,6 @@
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_HIBERNATION, OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION);
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
- EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
- OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION);
- APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_POWER_RESTRICTIONS, OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS);
}
@@ -843,6 +882,7 @@
final UserManagerInternal mUserManagerInternal;
final UsageStatsManagerInternal mUsageStatsManagerInternal;
final TelephonyManager mTelephonyManager;
+ final RoleManager mRoleManager;
private final LockPatternUtils mLockPatternUtils;
private final LockSettingsInternal mLockSettingsInternal;
private final DeviceAdminServiceController mDeviceAdminServiceController;
@@ -1630,6 +1670,10 @@
return mContext.getSystemService(TelephonyManager.class);
}
+ RoleManager getRoleManager() {
+ return mContext.getSystemService(RoleManager.class);
+ }
+
TrustManager getTrustManager() {
return (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
}
@@ -1972,6 +2016,7 @@
mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
+ mRoleManager = Objects.requireNonNull(injector.getRoleManager());
mLocalService = new LocalService();
mLockPatternUtils = injector.newLockPatternUtils();
@@ -4503,15 +4548,28 @@
}
@Override
- public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- Objects.requireNonNull(admin, "ComponentName is null");
+ public boolean addCrossProfileWidgetProvider(ComponentName admin, String callerPackageName,
+ String packageName) {
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
+ ActiveAdmin activeAdmin;
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ caller.getPackageName(),
+ caller.getUserId());
+ activeAdmin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ synchronized (getLockObject()) {
+ activeAdmin = getProfileOwnerLocked(caller.getUserId());
+ }
+ }
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerLocked(caller.getUserId());
if (activeAdmin.crossProfileWidgetProviders == null) {
activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
}
@@ -4525,7 +4583,7 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ADD_CROSS_PROFILE_WIDGET_PROVIDER)
- .setAdmin(admin)
+ .setAdmin(caller.getPackageName())
.write();
if (changedProviders != null) {
@@ -4538,15 +4596,28 @@
}
@Override
- public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- Objects.requireNonNull(admin, "ComponentName is null");
+ public boolean removeCrossProfileWidgetProvider(ComponentName admin, String callerPackageName,
+ String packageName) {
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
+ ActiveAdmin activeAdmin;
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ caller.getPackageName(),
+ caller.getUserId());
+ activeAdmin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ synchronized (getLockObject()) {
+ activeAdmin = getProfileOwnerLocked(caller.getUserId());
+ }
+ }
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerLocked(caller.getUserId());
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return false;
@@ -4560,7 +4631,7 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.REMOVE_CROSS_PROFILE_WIDGET_PROVIDER)
- .setAdmin(admin)
+ .setAdmin(caller.getPackageName())
.write();
if (changedProviders != null) {
@@ -4573,14 +4644,27 @@
}
@Override
- public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
- Objects.requireNonNull(admin, "ComponentName is null");
+ public List<String> getCrossProfileWidgetProviders(ComponentName admin,
+ String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
+ ActiveAdmin activeAdmin;
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ caller.getPackageName(),
+ caller.getUserId());
+ activeAdmin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
+ synchronized (getLockObject()) {
+ activeAdmin = getProfileOwnerLocked(caller.getUserId());
+ }
+ }
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerLocked(caller.getUserId());
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
@@ -4923,7 +5007,8 @@
synchronized (getLockObject()) {
if (isPermissionCheckFlagEnabled()) {
int affectedUser = parent ? getProfileParentId(userHandle) : userHandle;
- enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, affectedUser);
+ enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ /*callerPackageName=*/ null, affectedUser);
} else {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -5211,7 +5296,8 @@
if (isPermissionCheckFlagEnabled()) {
int affectedUser = calledOnParent ? getProfileParentId(caller.getUserId())
: caller.getUserId();
- enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, affectedUser);
+ enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ /*callerPackageName=*/ null, affectedUser);
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller) || isProfileOwner(caller));
@@ -5257,7 +5343,8 @@
if (!hasCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)) {
if (isPermissionCheckFlagEnabled()) {
int affectedUser = parent ? getProfileParentId(userHandle) : userHandle;
- enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, affectedUser);
+ enforcePermission(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ /*callerPackageName=*/ null, affectedUser);
} else {
getActiveAdminForCallerLocked(
null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
@@ -5994,9 +6081,16 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
final boolean isCallerDelegate = isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
final boolean isCredentialManagementApp = isCredentialManagementApp(caller);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ if (isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(
+ hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES,
+ caller.getPackageName(), caller.getUserId())
+ || isCredentialManagementApp);
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ }
if (isCredentialManagementApp) {
Preconditions.checkCallAuthorization(!isUserSelectable, "The credential "
+ "management app is not allowed to install a user selectable key pair");
@@ -6059,9 +6153,16 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
final boolean isCallerDelegate = isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
final boolean isCredentialManagementApp = isCredentialManagementApp(caller);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ if (isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(
+ hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES,
+ caller.getPackageName(), caller.getUserId())
+ || isCredentialManagementApp);
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ }
if (isCredentialManagementApp) {
Preconditions.checkCallAuthorization(
isAliasInCredentialManagementAppPolicy(caller, alias),
@@ -6124,8 +6225,13 @@
}
private boolean canInstallCertificates(CallerIdentity caller) {
- return isProfileOwner(caller) || isDefaultDeviceOwner(caller)
- || isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
+ if (isPermissionCheckFlagEnabled()) {
+ return hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES,
+ caller.getPackageName(), caller.getUserId());
+ } else {
+ return isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
+ }
}
private boolean canChooseCertificates(CallerIdentity caller) {
@@ -6318,9 +6424,16 @@
caller.getPackageName(), caller.getUid()));
enforceIndividualAttestationSupportedIfRequested(attestationUtilsFlags);
} else {
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ if (isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(
+ hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES,
+ caller.getPackageName(), caller.getUserId())
+ || isCredentialManagementApp);
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(
+ caller) || isDefaultDeviceOwner(caller))) || (caller.hasPackage() && (
+ isCallerDelegate || isCredentialManagementApp)));
+ }
if (isCredentialManagementApp) {
Preconditions.checkCallAuthorization(
isAliasInCredentialManagementAppPolicy(caller, alias),
@@ -6453,9 +6566,16 @@
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
final boolean isCallerDelegate = isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
final boolean isCredentialManagementApp = isCredentialManagementApp(caller);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ if (isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(
+ hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES,
+ caller.getPackageName(), caller.getUserId())
+ || isCredentialManagementApp);
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+ }
if (isCredentialManagementApp) {
Preconditions.checkCallAuthorization(
isAliasInCredentialManagementAppPolicy(caller, alias),
@@ -6851,7 +6971,9 @@
* @return {@code true} if the calling process is a delegate of {@code scope}.
*/
private boolean isCallerDelegate(CallerIdentity caller, String scope) {
- Objects.requireNonNull(caller.getPackageName(), "callerPackage is null");
+ if (caller.getPackageName() == null) {
+ return false;
+ }
Preconditions.checkArgument(Arrays.asList(DELEGATIONS).contains(scope),
"Unexpected delegation scope: %s", scope);
@@ -6866,6 +6988,31 @@
}
/**
+ * Check whether a caller application has been delegated any scope via
+ * {@link #setDelegatedScopes} to access privileged APIs on the behalf of a profile owner or
+ * device owner.
+ * <p>
+ * This is done by checking that the calling package was granted any scope delegations and
+ * then comparing the calling UID with the UID of the calling package as reported by
+ * {@link PackageManager#getPackageUidAsUser}.
+ *
+ * @param caller the calling identity
+ * @return {@code true} if the calling process is a delegate of any scope.
+ */
+ private boolean isCallerDelegate(CallerIdentity caller) {
+ Objects.requireNonNull(caller.getPackageName(), "callerPackage is null");
+
+ synchronized (getLockObject()) {
+ // Retrieve user policy data.
+ final DevicePolicyData policy = getUserData(caller.getUserId());
+ // Retrieve the list of delegation scopes granted to callerPackage.
+ final List<String> scopes = policy.mDelegationMap.get(caller.getPackageName());
+ // Check callingUid only if callerPackage has the required scope delegation.
+ return scopes != null;
+ }
+ }
+
+ /**
* Helper function to preserve delegation behavior pre-O when using the deprecated functions
* {@code #setCertInstallerPackage} and {@code #setApplicationRestrictionsManagingPackage}.
*/
@@ -7214,31 +7361,41 @@
}
@Override
- public void wipeDataWithReason(int flags, @NonNull String wipeReasonForUser,
- boolean calledOnParentInstance, boolean factoryReset) {
+ public void wipeDataWithReason(String callerPackageName, int flags,
+ @NonNull String wipeReasonForUser, boolean calledOnParentInstance,
+ boolean factoryReset) {
if (!mHasFeature && !hasCallingOrSelfPermission(permission.MASTER_CLEAR)) {
return;
}
- final CallerIdentity caller = getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentity(callerPackageName);
+ ActiveAdmin admin;
+
boolean calledByProfileOwnerOnOrgOwnedDevice =
isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId());
- if (calledOnParentInstance) {
- Preconditions.checkCallAuthorization(calledByProfileOwnerOnOrgOwnedDevice,
- "Wiping the entire device can only be done by a profile owner on "
- + "organization-owned device.");
- }
- if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || calledByProfileOwnerOnOrgOwnedDevice
- || isFinancedDeviceOwner(caller),
- "Only device owners or profile owners of organization-owned device can set "
- + "WIPE_RESET_PROTECTION_DATA");
- }
-
- final ActiveAdmin admin;
- synchronized (getLockObject()) {
- admin = getActiveAdminWithPolicyForUidLocked(/* who= */ null,
- DeviceAdminInfo.USES_POLICY_WIPE_DATA, caller.getUid());
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /*admin=*/ null,
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ caller.getPackageName(),
+ factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ if (calledOnParentInstance) {
+ Preconditions.checkCallAuthorization(calledByProfileOwnerOnOrgOwnedDevice,
+ "Wiping the entire device can only be done by a profile owner on "
+ + "organization-owned device.");
+ }
+ if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || calledByProfileOwnerOnOrgOwnedDevice
+ || isFinancedDeviceOwner(caller),
+ "Only device owners or profile owners of organization-owned device can set "
+ + "WIPE_RESET_PROTECTION_DATA");
+ }
+ synchronized (getLockObject()) {
+ admin = getActiveAdminWithPolicyForUidLocked(/* who= */ null,
+ DeviceAdminInfo.USES_POLICY_WIPE_DATA, caller.getUid());
+ }
}
Preconditions.checkCallAuthorization(
@@ -8484,18 +8641,19 @@
* Set whether auto time is enabled on the device.
*/
@Override
- public void setAutoTimeEnabled(ComponentName who, boolean enabled) {
+ public void setAutoTimeEnabled(@Nullable ComponentName who, String callerPackageName,
+ boolean enabled) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
// The effect of this policy is device-wide.
- enforcePermission(SET_TIME, UserHandle.USER_ALL);
+ enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
caller));
@@ -8505,7 +8663,7 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME)
- .setAdmin(caller.getComponentName())
+ .setAdmin(caller.getPackageName())
.setBoolean(enabled)
.write();
}
@@ -8514,17 +8672,17 @@
* Returns whether auto time is used on the device or not.
*/
@Override
- public boolean getAutoTimeEnabled(ComponentName who) {
+ public boolean getAutoTimeEnabled(@Nullable ComponentName who, String callerPackageName) {
if (!mHasFeature) {
return false;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
- enforceCanQuery(SET_TIME, UserHandle.USER_ALL);
+ enforceCanQuery(caller.getPackageName(), SET_TIME, UserHandle.USER_ALL);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
caller));
@@ -8537,39 +8695,40 @@
* Set whether auto time zone is enabled on the device.
*/
@Override
- public void setAutoTimeZoneEnabled(ComponentName who, boolean enabled) {
+ public void setAutoTimeZoneEnabled(@Nullable ComponentName who, String callerPackageName,
+ boolean enabled) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
-
- if (isPermissionCheckFlagEnabled()) {
- // The effect of this policy is device-wide.
- enforcePermission(SET_TIME_ZONE, UserHandle.USER_ALL);
- } else {
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
- }
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ // The effect of this policy is device-wide.
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ SET_TIME_ZONE,
+ caller.getPackageName(),
+ UserHandle.USER_ALL
+ );
mDevicePolicyEngine.setGlobalPolicy(
PolicyDefinition.AUTO_TIMEZONE,
// TODO(b/260573124): add correct enforcing admin when permission changes are
// merged.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()),
+ enforcingAdmin,
new BooleanPolicyValue(enabled));
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
+ caller));
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
- .setAdmin(caller.getComponentName())
+ .setAdmin(caller.getPackageName())
.setBoolean(enabled)
.write();
}
@@ -8578,18 +8737,18 @@
* Returns whether auto time zone is used on the device or not.
*/
@Override
- public boolean getAutoTimeZoneEnabled(ComponentName who) {
+ public boolean getAutoTimeZoneEnabled(@Nullable ComponentName who, String callerPackageName) {
if (!mHasFeature) {
return false;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
// The effect of this policy is device-wide.
- enforceCanQuery(SET_TIME_ZONE, UserHandle.USER_ALL);
+ enforceCanQuery(caller.getPackageName(), SET_TIME_ZONE, UserHandle.USER_ALL);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
caller));
@@ -8752,16 +8911,16 @@
}
final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
- final int userHandle = caller.getUserId();
+ final int userId = caller.getUserId();
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED);
- ActiveAdmin admin = null;
+ ActiveAdmin admin;
if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_CAMERA,
caller.getPackageName(),
- getProfileParentUserIfRequested(userHandle, parent));
+ getProfileParentUserIfRequested(userId, parent));
admin = enforcingAdmin.getActiveAdmin();
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8778,20 +8937,20 @@
synchronized (getLockObject()) {
if (admin.disableCamera != disabled) {
admin.disableCamera = disabled;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(userId);
}
}
// Tell the user manager that the restrictions have changed.
- pushUserRestrictions(userHandle);
+ pushUserRestrictions(userId);
- final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ final int affectedUserId = parent ? getProfileParentId(userId) : userId;
if (SecurityLog.isLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_CAMERA_POLICY_SET,
- who.getPackageName(), userHandle, affectedUserId, disabled ? 1 : 0);
+ who.getPackageName(), userId, affectedUserId, disabled ? 1 : 0);
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_CAMERA_DISABLED)
- .setAdmin(caller.getComponentName())
+ .setAdmin(caller.getPackageName())
.setBoolean(disabled)
.setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
@@ -8802,16 +8961,19 @@
* active admins.
*/
@Override
- public boolean getCameraDisabled(ComponentName who, int userHandle, boolean parent) {
+ public boolean getCameraDisabled(ComponentName who, String callerPackageName, int userHandle,
+ boolean parent) {
if (!mHasFeature) {
return false;
}
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(
- hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller)
- || hasPermission(MANAGE_DEVICE_POLICY_CAMERA, userHandle)
- || hasPermission(QUERY_ADMIN_POLICY));
+ hasFullCrossUsersPermission(caller, userHandle)
+ || isCameraServerUid(caller)
+ || hasPermission(MANAGE_DEVICE_POLICY_CAMERA,
+ caller.getPackageName(), userHandle)
+ || hasPermission(QUERY_ADMIN_POLICY, caller.getPackageName()));
} else {
Preconditions.checkCallAuthorization(
hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller));
@@ -10170,6 +10332,8 @@
* (2.1.1) The caller is the profile owner.
* (2.1.2) The caller is from another app in the same user as the profile owner, AND
* the caller is the delegated cert installer.
+ * (3) The caller holds the
+ * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CERTIFICATES} permission.
*
* For the device owner case, simply check that the caller is the device owner or the
* delegated certificate installer.
@@ -10182,19 +10346,23 @@
*/
@VisibleForTesting
boolean hasDeviceIdAccessUnchecked(String packageName, int uid) {
- ComponentName deviceOwner = getDeviceOwnerComponent(true);
- if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
- || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
- return true;
- }
final int userId = UserHandle.getUserId(uid);
- ComponentName profileOwner = getProfileOwnerAsUser(userId);
- final boolean isCallerProfileOwnerOrDelegate = profileOwner != null
- && (profileOwner.getPackageName().equals(packageName)
- || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL));
- if (isCallerProfileOwnerOrDelegate && (isProfileOwnerOfOrganizationOwnedDevice(userId)
- || isUserAffiliatedWithDevice(userId))) {
- return true;
+ if (isPermissionCheckFlagEnabled()) {
+ return hasPermission(MANAGE_DEVICE_POLICY_CERTIFICATES, packageName, userId);
+ } else {
+ ComponentName deviceOwner = getDeviceOwnerComponent(true);
+ if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
+ || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+ return true;
+ }
+ ComponentName profileOwner = getProfileOwnerAsUser(userId);
+ final boolean isCallerProfileOwnerOrDelegate = profileOwner != null
+ && (profileOwner.getPackageName().equals(packageName)
+ || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL));
+ if (isCallerProfileOwnerOrDelegate && (isProfileOwnerOfOrganizationOwnedDevice(userId)
+ || isUserAffiliatedWithDevice(userId))) {
+ return true;
+ }
}
return false;
}
@@ -10452,6 +10620,33 @@
}
}
+ private void enforceCanQueryLockTaskLocked(ComponentName who, String callerPackageName) {
+ CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final int userId = caller.getUserId();
+
+ enforceCanQuery(caller.getPackageName(), MANAGE_DEVICE_POLICY_LOCK_TASK, userId);
+ if (!canUserUseLockTaskLocked(userId)) {
+ throw new SecurityException("User " + userId + " is not allowed to use lock task");
+ }
+ }
+
+ private EnforcingAdmin enforceCanCallLockTaskLocked(ComponentName who,
+ String callerPackageName) {
+ CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final int userId = caller.getUserId();
+
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ caller.getPackageName(),
+ userId
+ );
+ if (!canUserUseLockTaskLocked(userId)) {
+ throw new SecurityException("User " + userId + " is not allowed to use lock task");
+ }
+ return enforcingAdmin;
+ }
+
private boolean isSystemUid(CallerIdentity caller) {
return UserHandle.isSameApp(caller.getUid(), Process.SYSTEM_UID);
}
@@ -10702,26 +10897,38 @@
}
@Override
- public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
- ComponentName activity) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller)
- || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+ public void addPersistentPreferredActivity(ComponentName who, String callerPackageName,
+ IntentFilter filter, ComponentName activity) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
- final int userHandle = caller.getUserId();
+ final int userId = caller.getUserId();
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin;
+ if (who == null) {
+ enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ caller.getPackageName(),
+ userId);
+ } else {
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+ enforcingAdmin = getEnforcingAdminForCaller(who, callerPackageName);
+ }
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(filter),
- EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
+ enforcingAdmin,
new ComponentNamePolicyValue(activity),
- userHandle);
+ userId);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
- mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
- mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
+ mIPackageManager.addPersistentPreferredActivity(filter, activity, userId);
+ mIPackageManager.flushPackageRestrictionsAsUser(userId);
} catch (RemoteException re) {
// Shouldn't happen
Slog.wtf(LOG_TAG, "Error adding persistent preferred activity", re);
@@ -10734,32 +10941,44 @@
(activity != null ? activity.getPackageName() : null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ADD_PERSISTENT_PREFERRED_ACTIVITY)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.setStrings(activityPackage, getIntentFilterActions(filter))
.write();
}
@Override
- public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller)
- || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
-
- final int userHandle = caller.getUserId();
+ public void clearPackagePersistentPreferredActivities(ComponentName who,
+ String callerPackageName, String packageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final int userId = caller.getUserId();
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin;
+ if (who == null) {
+ enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ caller.getPackageName(),
+ userId);
+ } else {
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+ enforcingAdmin = getEnforcingAdminForCaller(who, callerPackageName);
+ }
clearPackagePersistentPreferredActivitiesFromPolicyEngine(
- EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
+ enforcingAdmin,
packageName,
- userHandle);
+ userId);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
mIPackageManager.clearPackagePersistentPreferredActivities(packageName,
- userHandle);
- mIPackageManager.flushPackageRestrictionsAsUser(userHandle);
+ userId);
+ mIPackageManager.flushPackageRestrictionsAsUser(userId);
} catch (RemoteException re) {
// Shouldn't happen
Slogf.wtf(
@@ -10807,19 +11026,86 @@
}
@Override
- public void setDefaultSmsApplication(ComponentName admin, String packageName, boolean parent) {
- Objects.requireNonNull(admin, "ComponentName is null");
+ public void setDefaultSmsApplication(ComponentName admin, String callerPackageName,
+ String packageName, boolean parent) {
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
+ final int userId;
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
+ if (isPermissionCheckFlagEnabled()) {
+ enforcePermission(
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ caller.getPackageName(),
+ getAffectedUser(parent));
+ } else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
+ }
if (parent) {
+ userId = getProfileParentId(mInjector.userHandleGetCallingUserId());
mInjector.binderWithCleanCallingIdentity(() -> enforcePackageIsSystemPackage(
- packageName, getProfileParentId(mInjector.userHandleGetCallingUserId())));
+ packageName, userId));
+ } else {
+ userId = mInjector.userHandleGetCallingUserId();
}
mInjector.binderWithCleanCallingIdentity(() ->
- SmsApplication.setDefaultApplication(packageName, mContext));
+ SmsApplication.setDefaultApplicationAsUser(packageName, mContext, userId));
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+ getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ if (!Objects.equals(activeAdmin.mSmsPackage, packageName)) {
+ activeAdmin.mSmsPackage = packageName;
+ saveSettingsLocked(caller.getUserId());
+ }
+ }
+ }
+
+ @Override
+ public void setDefaultDialerApplication(String packageName) {
+ if (!mHasFeature || !mHasTelephonyFeature) {
+ return;
+ }
+
+ final CallerIdentity caller = getCallerIdentity();
+ final int callerUserId = caller.getUserId();
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ Consumer<Boolean> callback = successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new IllegalArgumentException(
+ packageName + " cannot be set as the dialer"));
+ }
+ };
+ mRoleManager.addRoleHolderAsUser(
+ RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(callerUserId),
+ AsyncTask.THREAD_POOL_EXECUTOR, callback);
+ try {
+ future.get(5, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ throw new IllegalArgumentException("Timeout when setting the app as the dialer", e);
+ } catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof IllegalArgumentException) {
+ throw (IllegalArgumentException) cause;
+ } else {
+ throw new IllegalStateException(cause);
+ }
+ }
+ });
+ // Only save the package when the setting the role succeeded without exception.
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(callerUserId);
+ if (!Objects.equals(admin.mDialerPackage, packageName)) {
+ admin.mDialerPackage = packageName;
+ saveSettingsLocked(callerUserId);
+ }
+ }
}
@Override
@@ -10850,12 +11136,15 @@
public void setApplicationRestrictions(ComponentName who, String callerPackage,
String packageName, Bundle restrictions) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS)));
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
if (useDevicePolicyEngine(caller, DELEGATION_APP_RESTRICTIONS)) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ caller.getPackageName(),
+ caller.getUserId()
+ );
// This check is eventually made in UMS, checking here to fail early.
String validationResult =
FrameworkParsingPackageUtils.validateName(packageName, false, false);
@@ -10863,27 +11152,26 @@
throw new IllegalArgumentException("Invalid package name: " + validationResult);
}
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- who == null
- ? new ComponentName(caller.getPackageName(), "Delegate")
- : who,
- caller.getUserId());
-
if (restrictions == null || restrictions.isEmpty()) {
mDevicePolicyEngine.removeLocalPolicy(
PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
- admin,
+ enforcingAdmin,
caller.getUserId());
} else {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
- admin,
+ enforcingAdmin,
new BundlePolicyValue(restrictions),
caller.getUserId());
}
setBackwardsCompatibleAppRestrictions(
packageName, restrictions, caller.getUserHandle());
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_APP_RESTRICTIONS)));
mInjector.binderWithCleanCallingIdentity(() -> {
mUserManager.setApplicationRestrictions(packageName, restrictions,
caller.getUserHandle());
@@ -10921,6 +11209,17 @@
? null : policies.entrySet().stream().findAny().get().getValue().getValue();
}
+ private int getUidForPackage(String packageName, int userId) {
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ try {
+ return mContext.getPackageManager().getApplicationInfoAsUser(
+ packageName, /* flags= */ 0, userId).uid;
+ } catch (NameNotFoundException exception) {
+ return -1;
+ }
+ });
+ }
+
@Override
public void setTrustAgentConfiguration(
ComponentName admin, String callerPackageName, ComponentName agent,
@@ -11040,12 +11339,21 @@
}
@Override
- public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ public void addCrossProfileIntentFilter(ComponentName who, String callerPackageName,
+ IntentFilter filter, int flags) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
int callingUserId = caller.getUserId();
+
+ if (isPermissionCheckFlagEnabled()) {
+ enforcePermission(
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ caller.getPackageName(),
+ callingUserId);
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ }
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
@@ -11072,7 +11380,7 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ADD_CROSS_PROFILE_INTENT_FILTER)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.setStrings(getIntentFilterActions(filter))
.setInt(flags)
.write();
@@ -11091,13 +11399,21 @@
}
@Override
- public void clearCrossProfileIntentFilters(ComponentName who) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
-
+ public void clearCrossProfileIntentFilters(ComponentName who, String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
int callingUserId = caller.getUserId();
+
+ if (isPermissionCheckFlagEnabled()) {
+ enforcePermission(
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ caller.getPackageName(),
+ callingUserId);
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ }
+
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
@@ -12166,24 +12482,29 @@
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS)));
if (useDevicePolicyEngine(caller, DELEGATION_APP_RESTRICTIONS)) {
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- who != null ? who : new ComponentName(callerPackage, "Delegate"),
- caller.getUserId());
+ EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ caller.getPackageName(),
+ caller.getUserId()
+ );
LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
caller.getUserId());
- if (policies.isEmpty() || !policies.containsKey(admin)) {
+ if (policies.isEmpty() || !policies.containsKey(enforcingAdmin)) {
return Bundle.EMPTY;
}
- return policies.get(admin).getValue();
+ return policies.get(enforcingAdmin).getValue();
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_APP_RESTRICTIONS)));
return mInjector.binderWithCleanCallingIdentity(() -> {
Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
caller.getUserHandle());
@@ -12230,11 +12551,25 @@
@Override
public String[] setPackagesSuspended(ComponentName who, String callerPackage,
String[] packageNames, boolean suspended) {
- Objects.requireNonNull(packageNames, "array of packages cannot be null");
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
+ ActiveAdmin admin;
+
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ caller.getPackageName(),
+ caller.getUserId());
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_PACKAGE_ACCESS)));
+ synchronized (getLockObject()) {
+ admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ }
+ }
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_PACKAGES_SUSPENDED);
// Must remove the exempt apps from the input before calling PM, then add them back to
@@ -12276,7 +12611,6 @@
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
ArraySet<String> current = new ArraySet<>(admin.suspendedPackages);
if (suspended) {
current.addAll(changed);
@@ -12316,9 +12650,18 @@
@Override
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
+
+ if (isPermissionCheckFlagEnabled()) {
+ enforcePermission(
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ caller.getPackageName(),
+ caller.getUserId());
+ } else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_PACKAGE_ACCESS)));
+ }
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
@@ -12368,52 +12711,21 @@
public void setUserRestriction(
ComponentName who, String callerPackage, String key, boolean enabledFromThisOwner,
boolean parent) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ int userId = caller.getUserId();
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
- if (parent) {
- Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
- } else {
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
- }
- int userId = caller.getUserId();
- synchronized (getLockObject()) {
- if (isDefaultDeviceOwner(caller)) {
- if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
- throw new SecurityException("Device owner cannot set user restriction " + key);
- }
- Preconditions.checkArgument(!parent,
- "Cannot use the parent instance in Device Owner mode");
- } else if (isFinancedDeviceOwner(caller)) {
- if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) {
- throw new SecurityException("Cannot set user restriction " + key
- + " when managing a financed device");
- }
- Preconditions.checkArgument(!parent,
- "Cannot use the parent instance in Financed Device Owner mode");
- } else {
- boolean profileOwnerCanChangeOnItself = !parent
- && UserRestrictionsUtils.canProfileOwnerChange(
- key, userId == getMainUserId());
- boolean orgOwnedProfileOwnerCanChangeGlobally = parent
- && isProfileOwnerOfOrganizationOwnedDevice(caller)
- && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
- key);
-
- if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
- throw new SecurityException("Profile owner cannot set user restriction " + key);
- }
- }
- }
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- who, caller.getUserId());
+ EnforcingAdmin admin = enforcePermissionForUserRestriction(
+ who,
+ key,
+ caller.getPackageName(),
+ userId);
PolicyDefinition<Boolean> policyDefinition =
PolicyDefinition.getPolicyDefinitionForUserRestriction(key);
if (enabledFromThisOwner) {
@@ -12445,6 +12757,45 @@
}
}
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ if (parent) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller));
+ } else {
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwner(caller));
+ }
+ synchronized (getLockObject()) {
+ if (isDefaultDeviceOwner(caller)) {
+ if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
+ throw new SecurityException("Device owner cannot set user restriction "
+ + key);
+ }
+ Preconditions.checkArgument(!parent,
+ "Cannot use the parent instance in Device Owner mode");
+ } else if (isFinancedDeviceOwner(caller)) {
+ if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) {
+ throw new SecurityException("Cannot set user restriction " + key
+ + " when managing a financed device");
+ }
+ Preconditions.checkArgument(!parent,
+ "Cannot use the parent instance in Financed Device Owner"
+ + " mode");
+ } else {
+ boolean profileOwnerCanChangeOnItself = !parent
+ && UserRestrictionsUtils.canProfileOwnerChange(
+ key, userId == getMainUserId());
+ boolean orgOwnedProfileOwnerCanChangeGlobally = parent
+ && isProfileOwnerOfOrganizationOwnedDevice(caller)
+ && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+ key);
+
+ if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
+ throw new SecurityException("Profile owner cannot set user restriction "
+ + key);
+ }
+ }
+ }
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
getProfileOwnerOrDeviceOwnerLocked(userId), parent);
@@ -12464,42 +12815,22 @@
@Override
public void setUserRestrictionGlobally(String callerPackage, String key) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- // TODO: Replace with new permission checks, for now copying this over from
- // setUserRestriction
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
int userHandle = caller.getUserId();
- if (isDefaultDeviceOwner(caller)) {
- if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
- throw new SecurityException("Device owner cannot set user restriction " + key);
- }
- } else if (isFinancedDeviceOwner(caller)) {
- if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) {
- throw new SecurityException("Cannot set user restriction " + key
- + " when managing a financed device");
- }
- } else {
- boolean profileOwnerCanChangeOnItself =
- UserRestrictionsUtils.canProfileOwnerChange(key, userHandle == getMainUserId());
- boolean orgOwnedProfileOwnerCanChangeGlobally =
- isProfileOwnerOfOrganizationOwnedDevice(caller)
- && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
- key);
-
- if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
- throw new SecurityException("Profile owner cannot set user restriction " + key);
- }
- }
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
throw new IllegalStateException("One or more admins are not targeting Android 14.");
}
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getPackageName(), caller.getUserId());
+ EnforcingAdmin admin = enforcePermissionForUserRestriction(
+ /*who=*/ null,
+ key,
+ caller.getPackageName(),
+ caller.getUserId()
+ );
mDevicePolicyEngine.setGlobalPolicy(
PolicyDefinition.getPolicyDefinitionForUserRestriction(key),
@@ -12597,19 +12928,20 @@
if (!mHasFeature) {
return null;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller)
- || isProfileOwner(caller)
- || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage);
return getUserRestrictionsFromPolicyEngine(
- EnforcingAdmin.createEnterpriseEnforcingAdmin(who, caller.getUserId()),
+ admin,
parent ? getProfileParentId(caller.getUserId()) : caller.getUserId());
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isFinancedDeviceOwner(caller)
+ || isProfileOwner(caller)
+ || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
@@ -12618,6 +12950,169 @@
}
}
+ // Map of user restriction to permission.
+ private static final HashMap<String, String> USER_RESTRICTION_PERMISSIONS = new HashMap<>();
+ {
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.ENSURE_VERIFY_APPS, MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_WIFI_TETHERING, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_WIFI_DIRECT, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_USER_SWITCH, MANAGE_DEVICE_POLICY_USERS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_USB_FILE_TRANSFER, MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_UNMUTE_MICROPHONE, MANAGE_DEVICE_POLICY_MICROPHONE);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_UNMUTE_DEVICE, MANAGE_DEVICE_POLICY_AUDIO_OUTPUT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_UNINSTALL_APPS, MANAGE_DEVICE_POLICY_APPS_CONTROL);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_UNIFIED_PASSWORD, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SMS, MANAGE_DEVICE_POLICY_SMS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SHARE_LOCATION, MANAGE_DEVICE_POLICY_LOCATION);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SET_WALLPAPER, MANAGE_DEVICE_POLICY_WALLPAPER);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SET_USER_ICON, MANAGE_DEVICE_POLICY_USERS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_SAFE_BOOT, MANAGE_DEVICE_POLICY_SAFE_BOOT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_RUN_IN_BACKGROUND, MANAGE_DEVICE_POLICY_SAFE_BOOT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_REMOVE_USER, MANAGE_DEVICE_POLICY_USERS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_PRINTING, MANAGE_DEVICE_POLICY_PRINTING);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_OUTGOING_CALLS, MANAGE_DEVICE_POLICY_CALLS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_OUTGOING_BEAM, MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_NETWORK_RESET, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_MODIFY_ACCOUNTS, MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_MICROPHONE_TOGGLE, MANAGE_DEVICE_POLICY_MICROPHONE);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_INSTALL_APPS, MANAGE_DEVICE_POLICY_APPS_CONTROL);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_FUN, MANAGE_DEVICE_POLICY_FUN);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_FACTORY_RESET, MANAGE_DEVICE_POLICY_FACTORY_RESET);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_DATA_ROAMING, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CREATE_WINDOWS, MANAGE_DEVICE_POLICY_WINDOWS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONTENT_SUGGESTIONS, MANAGE_DEVICE_POLICY_SCREEN_CONTENT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONTENT_CAPTURE, MANAGE_DEVICE_POLICY_SCREEN_CONTENT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_WIFI, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_VPN, MANAGE_DEVICE_POLICY_VPN);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_TETHERING, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, MANAGE_DEVICE_POLICY_DISPLAY);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS, MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_LOCATION, MANAGE_DEVICE_POLICY_LOCATION);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_LOCALE, MANAGE_DEVICE_POLICY_LOCALE);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_DATE_TIME, MANAGE_DEVICE_POLICY_TIME);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_CREDENTIALS, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_BRIGHTNESS, MANAGE_DEVICE_POLICY_DISPLAY);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_BLUETOOTH, MANAGE_DEVICE_POLICY_BLUETOOTH);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CHANGE_WIFI_STATE, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CAMERA_TOGGLE, MANAGE_DEVICE_POLICY_CAMERA);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CAMERA, MANAGE_DEVICE_POLICY_CAMERA);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_BLUETOOTH_SHARING, MANAGE_DEVICE_POLICY_BLUETOOTH);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_BLUETOOTH, MANAGE_DEVICE_POLICY_BLUETOOTH);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_BIOMETRIC, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_AUTOFILL, MANAGE_DEVICE_POLICY_AUTOFILL);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_APPS_CONTROL, MANAGE_DEVICE_POLICY_APPS_CONTROL);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_AMBIENT_DISPLAY, MANAGE_DEVICE_POLICY_DISPLAY);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_AIRPLANE_MODE, MANAGE_DEVICE_POLICY_AIRPLANE_MODE);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ADJUST_VOLUME, MANAGE_DEVICE_POLICY_AUDIO_OUTPUT);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ADD_WIFI_CONFIG, MANAGE_DEVICE_POLICY_WIFI);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ADD_USER, MANAGE_DEVICE_POLICY_USERS);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ADD_CLONE_PROFILE, MANAGE_DEVICE_POLICY_PROFILES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, MANAGE_DEVICE_POLICY_PROFILES);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CELLULAR_2G, MANAGE_DEVICE_POLICY_MOBILE_NETWORK);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION);
+
+ // Restrictions not allowed to be set by admins.
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_RECORD_AUDIO, null);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_WALLPAPER, null);
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_CONFIG_DEFAULT_APPS, null);
+ }
+
+ private EnforcingAdmin enforcePermissionForUserRestriction(ComponentName who,
+ String userRestriction, String callerPackageName, int userId) {
+ String permission = USER_RESTRICTION_PERMISSIONS.get(userRestriction);
+ if (permission != null) {
+ return enforcePermissionAndGetEnforcingAdmin(who, permission, callerPackageName,
+ userId);
+ }
+ throw new SecurityException("Admins are not permitted to set User Restriction: "
+ + userRestriction);
+ }
+
@Override
public Bundle getUserRestrictionsGlobally(String callerPackage) {
if (!mHasFeature) {
@@ -12627,15 +13122,10 @@
if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
throw new IllegalStateException("One or more admins are not targeting Android 14.");
}
- // TODO: Replace with new permission checks, for now copying this over from
- // setUserRestriction
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller)
- || isProfileOwner(caller));
- return getUserRestrictionsFromPolicyEngine(
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getPackageName(), caller.getUserId()),
+ EnforcingAdmin admin = getEnforcingAdminForCaller(/*who=*/ null, caller.getPackageName());
+
+ return getUserRestrictionsFromPolicyEngine(admin,
UserHandle.USER_ALL);
}
@@ -12664,7 +13154,7 @@
int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
if (isPermissionCheckFlagEnabled()) {
// TODO: We need to ensure the delegate with DELEGATION_PACKAGE_ACCESS can do this
- enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, userId);
+ enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
@@ -12718,7 +13208,7 @@
int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
if (isPermissionCheckFlagEnabled()) {
// TODO: Also support DELEGATION_PACKAGE_ACCESS
- enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, userId);
+ enforcePermission(MANAGE_DEVICE_POLICY_PACKAGE_STATE, caller.getPackageName(), userId);
} else {
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
@@ -12911,31 +13401,40 @@
}
@Override
- public void setAccountManagementDisabled(ComponentName who, String accountType,
- boolean disabled, boolean parent) {
+ public void setAccountManagementDisabled(ComponentName who, String callerPackageName,
+ String accountType, boolean disabled, boolean parent) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
synchronized (getLockObject()) {
- /*
- * When called on the parent DPM instance (parent == true), affects active admin
- * selection in two ways:
- * * The ActiveAdmin must be of an org-owned profile owner.
- * * The parent ActiveAdmin instance should be used for managing the restriction.
- */
final ActiveAdmin ap;
- if (parent) {
- ap = getParentOfAdminIfRequired(getOrganizationOwnedProfileOwnerLocked(caller),
- parent);
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ caller.getPackageName(),
+ getAffectedUser(parent)
+ );
+ ap = enforcingAdmin.getActiveAdmin();
} else {
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwner(caller));
- ap = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ Objects.requireNonNull(who, "ComponentName is null");
+ /*
+ * When called on the parent DPM instance (parent == true), affects active admin
+ * selection in two ways:
+ * * The ActiveAdmin must be of an org-owned profile owner.
+ * * The parent ActiveAdmin instance should be used for managing the restriction.
+ */
+ if (parent) {
+ ap = getParentOfAdminIfRequired(getOrganizationOwnedProfileOwnerLocked(caller),
+ parent);
+ } else {
+ Preconditions.checkCallAuthorization(
+ isDefaultDeviceOwner(caller) || isProfileOwner(caller));
+ ap = getParentOfAdminIfRequired(
+ getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ }
}
-
if (disabled) {
ap.accountTypesWithManagementDisabled.add(accountType);
} else {
@@ -12946,19 +13445,24 @@
}
@Override
- public String[] getAccountTypesWithManagementDisabled() {
- return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId(), false);
+ public String[] getAccountTypesWithManagementDisabled(String callerPackageName) {
+ return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId(),
+ callerPackageName, false);
}
@Override
- public String[] getAccountTypesWithManagementDisabledAsUser(int userId, boolean parent) {
+ public String[] getAccountTypesWithManagementDisabledAsUser(int userId,
+ String callerPackageName, boolean parent) {
if (!mHasFeature) {
return null;
}
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
-
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
+ final CallerIdentity caller = getCallerIdentity(callerPackageName);
+ if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, caller.getPackageName(), userId)
+ && !hasFullCrossUsersPermission(caller, userId)) {
+ throw new SecurityException("Caller does not have permission to call this on user: "
+ + userId);
+ }
synchronized (getLockObject()) {
final ArraySet<String> resultSet = new ArraySet<>();
@@ -12988,24 +13492,25 @@
public void setUninstallBlocked(ComponentName who, String callerPackage, String packageName,
boolean uninstallBlocked) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL)));
if (useDevicePolicyEngine(caller, DELEGATION_BLOCK_UNINSTALL)) {
- // TODO(b/260573124): Add correct enforcing admin when permission changes are
- // merged, and don't forget to handle delegates! Enterprise admins assume
- // component name isn't null.
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- who != null ? who : new ComponentName(callerPackage, "delegate"),
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ caller.getPackageName(),
caller.getUserId());
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PACKAGE_UNINSTALL_BLOCKED(packageName),
- admin,
+ enforcingAdmin,
new BooleanPolicyValue(uninstallBlocked),
caller.getUserId());
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+ || isFinancedDeviceOwner(caller)))
+ || (caller.hasPackage()
+ && isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL)));
final int userId = caller.getUserId();
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
@@ -13056,20 +13561,13 @@
}
@Override
- public boolean isUninstallBlocked(ComponentName who, String packageName) {
+ public boolean isUninstallBlocked(String packageName) {
// This function should return true if and only if the package is blocked by
// setUninstallBlocked(). It should still return false for other cases of blocks, such as
// when the package is a system app, or when it is an active device admin.
final int userId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
- //TODO: This is a silly access control check. Remove.
- if (who != null) {
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller));
- }
try {
return mIPackageManager.getBlockUninstallForUser(packageName, userId);
} catch (RemoteException re) {
@@ -13546,29 +14044,29 @@
}
@Override
- public void setLockTaskPackages(ComponentName who, String[] packages)
+ public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
throws SecurityException {
- Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packages, "packages is null");
- final CallerIdentity caller = getCallerIdentity(who);
-
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES);
synchronized (getLockObject()) {
enforceCanCallLockTaskLocked(caller);
- checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES);
}
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- who, caller.getUserId());
+ EnforcingAdmin enforcingAdmin;
+ synchronized (getLockObject()) {
+ enforcingAdmin = enforceCanCallLockTaskLocked(who, callerPackageName);
+ }
if (packages.length == 0) {
mDevicePolicyEngine.removeLocalPolicy(
PolicyDefinition.LOCK_TASK,
- admin,
+ enforcingAdmin,
caller.getUserId());
} else {
LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.LOCK_TASK,
- admin,
+ enforcingAdmin,
caller.getUserId());
LockTaskPolicy policy;
if (currentPolicy == null) {
@@ -13585,7 +14083,9 @@
caller.getUserId());
}
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
+ enforceCanCallLockTaskLocked(caller);
final int userHandle = caller.getUserId();
setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
}
@@ -13602,16 +14102,14 @@
}
@Override
- public String[] getLockTaskPackages(ComponentName who) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ public String[] getLockTaskPackages(ComponentName who, String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
final int userHandle = caller.getUserId();
- synchronized (getLockObject()) {
- enforceCanCallLockTaskLocked(caller);
- }
-
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ synchronized (getLockObject()) {
+ enforceCanQueryLockTaskLocked(who, caller.getPackageName());
+ }
LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.LOCK_TASK, userHandle);
if (policy == null) {
@@ -13620,7 +14118,9 @@
return policy.getPackages().toArray(new String[policy.getPackages().size()]);
}
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
+ enforceCanCallLockTaskLocked(caller);
final List<String> packages = getUserData(userHandle).mLockTaskPackages;
return packages.toArray(new String[packages.size()]);
}
@@ -13655,9 +14155,7 @@
}
@Override
- public void setLockTaskFeatures(ComponentName who, int flags) {
- Objects.requireNonNull(who, "ComponentName is null");
-
+ public void setLockTaskFeatures(ComponentName who, String callerPackageName, int flags) {
// Throw if Overview is used without Home.
boolean hasHome = (flags & LOCK_TASK_FEATURE_HOME) != 0;
boolean hasOverview = (flags & LOCK_TASK_FEATURE_OVERVIEW) != 0;
@@ -13667,18 +14165,20 @@
Preconditions.checkArgument(hasHome || !hasNotification,
"Cannot use LOCK_TASK_FEATURE_NOTIFICATIONS without LOCK_TASK_FEATURE_HOME");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
final int userHandle = caller.getUserId();
- synchronized (getLockObject()) {
- enforceCanCallLockTaskLocked(caller);
- enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
- checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES);
- }
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES);
+
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle);
+ EnforcingAdmin enforcingAdmin;
+ synchronized (getLockObject()) {
+ enforcingAdmin = enforceCanCallLockTaskLocked(who,
+ callerPackageName);
+ enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
+ }
LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.LOCK_TASK,
- admin,
+ enforcingAdmin,
caller.getUserId());
if (currentPolicy == null) {
throw new IllegalArgumentException("Can't set a lock task flags without setting "
@@ -13689,11 +14189,14 @@
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.LOCK_TASK,
- EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
+ enforcingAdmin,
policy,
caller.getUserId());
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
+ enforceCanCallLockTaskLocked(caller);
+ enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
setLockTaskFeaturesLocked(userHandle, flags);
}
}
@@ -13707,15 +14210,14 @@
}
@Override
- public int getLockTaskFeatures(ComponentName who) {
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ public int getLockTaskFeatures(ComponentName who, String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
final int userHandle = caller.getUserId();
- synchronized (getLockObject()) {
- enforceCanCallLockTaskLocked(caller);
- }
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ synchronized (getLockObject()) {
+ enforceCanQueryLockTaskLocked(who, caller.getPackageName());
+ }
LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
PolicyDefinition.LOCK_TASK, userHandle);
if (policy == null) {
@@ -13725,7 +14227,9 @@
}
return policy.getFlags();
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
+ enforceCanCallLockTaskLocked(caller);
return getUserData(userHandle).mLockTaskFeatures;
}
}
@@ -13879,7 +14383,8 @@
CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_WIFI, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_WIFI, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
Preconditions.checkNotNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(
@@ -13905,7 +14410,8 @@
}
CallerIdentity caller = getCallerIdentity(who);
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_WIFI, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_WIFI, /*callerPackageName=*/ null,
+ UserHandle.USER_ALL);
} else {
Preconditions.checkNotNull(who, "ComponentName is null");
@@ -13999,14 +14505,13 @@
}
@Override
- public boolean setTime(ComponentName who, long millis) {
- Objects.requireNonNull(who, "ComponentName is null");
-
- final CallerIdentity caller = getCallerIdentity(who);
+ public boolean setTime(@Nullable ComponentName who, String callerPackageName, long millis) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
// This is a global action.
- enforcePermission(SET_TIME, UserHandle.USER_ALL);
+ enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller));
@@ -14018,21 +14523,21 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME)
- .setAdmin(caller.getComponentName())
+ .setAdmin(caller.getPackageName())
.write();
mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
return true;
}
@Override
- public boolean setTimeZone(ComponentName who, String timeZone) {
- Objects.requireNonNull(who, "ComponentName is null");
-
- final CallerIdentity caller = getCallerIdentity(who);
+ public boolean setTimeZone(@Nullable ComponentName who, String callerPackageName,
+ String timeZone) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
// This is a global action.
- enforcePermission(SET_TIME_ZONE, UserHandle.USER_ALL);
+ enforcePermission(SET_TIME_ZONE, caller.getPackageName(), UserHandle.USER_ALL);
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller));
@@ -14049,7 +14554,7 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME_ZONE)
- .setAdmin(caller.getComponentName())
+ .setAdmin(caller.getPackageName())
.write();
return true;
}
@@ -14238,10 +14743,17 @@
}
@Override
- public boolean setStatusBarDisabled(ComponentName who, boolean disabled) {
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ public boolean setStatusBarDisabled(ComponentName who, String callerPackageName,
+ boolean disabled) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ if (isPermissionCheckFlagEnabled()) {
+ enforcePermission(MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(),
+ UserHandle.USER_ALL);
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ }
int userId = caller.getUserId();
synchronized (getLockObject()) {
@@ -14273,7 +14785,7 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_STATUS_BAR_DISABLED)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.setBoolean(disabled)
.write();
return true;
@@ -14674,13 +15186,15 @@
}
@Override
- public void enforcePermission(String permission, int targetUserId) {
- DevicePolicyManagerService.this.enforcePermission(permission, targetUserId);
+ public void enforcePermission(String callerPackage, String permission, int targetUserId) {
+ DevicePolicyManagerService.this.enforcePermission(permission, callerPackage,
+ targetUserId);
}
@Override
- public boolean hasPermission(String permission, int targetUserId) {
- return DevicePolicyManagerService.this.hasPermission(permission, targetUserId);
+ public boolean hasPermission(String callerPackage, String permission, int targetUserId) {
+ return DevicePolicyManagerService.this.hasPermission(permission, callerPackage,
+ targetUserId);
}
private void broadcastIntentToCrossProfileManifestReceivers(
@@ -14910,33 +15424,38 @@
}
@Override
- public Map<String, Bundle> getApplicationRestrictionsPerAdmin(
- String packageName, int userId) {
+ public List<Bundle> getApplicationRestrictionsPerAdminForUser(
+ String packageName, @UserIdInt int userId) {
+ if (UserHandle.getCallingUserId() != userId
+ || !UserHandle.isSameApp(
+ Binder.getCallingUid(), getUidForPackage(packageName, userId))) {
+ final int uid = Binder.getCallingUid();
+ if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+ throw new SecurityException("Only system may: get application restrictions for "
+ + "other user/app " + packageName);
+ }
+ }
LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
userId);
- Map<String, Bundle> restrictions = new HashMap<>();
+ List<Bundle> restrictions = new ArrayList<>();
for (EnforcingAdmin admin : policies.keySet()) {
- restrictions.put(admin.getPackageName(), policies.get(admin).getValue());
+ restrictions.add(policies.get(admin).getValue());
}
if (!restrictions.isEmpty()) {
return restrictions;
}
return mInjector.binderWithCleanCallingIdentity(() -> {
- // Could be a device that hasn't migrated yet, so just return any restrictions saved
- // in userManager.
+ // Could be a device that has a DPC that hasn't migrated yet, so just return any
+ // restrictions saved in userManager.
Bundle bundle = mUserManager.getApplicationRestrictions(
packageName, UserHandle.of(userId));
if (bundle == null || bundle.isEmpty()) {
- return new HashMap<>();
+ return new ArrayList<>();
}
- ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId);
- if (admin == null) {
- return new HashMap<>();
- }
- return Map.of(admin.info.getPackageName(), bundle);
+ return List.of(bundle);
});
}
}
@@ -15207,7 +15726,8 @@
synchronized (getLockObject()) {
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(caller)
@@ -15422,7 +15942,8 @@
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_PERMISSION_GRANT)));
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_PERMISSION_POLICY);
final int forUser = caller.getUserId();
@@ -15462,10 +15983,6 @@
Objects.requireNonNull(callback);
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_PERMISSION_GRANT_STATE);
synchronized (getLockObject()) {
@@ -15474,22 +15991,28 @@
}
}
if (useDevicePolicyEngine(caller, DELEGATION_PERMISSION_GRANT)) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ callerPackage,
+ caller.getUserId());
// TODO(b/266924257): decide how to handle the internal state if the package doesn't
// exist, or the permission isn't requested by the app, because we could end up with
// inconsistent state between the policy engine and package manager. Also a package
// might get removed or has it's permission updated after we've set the policy.
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.PERMISSION_GRANT(packageName, permission),
- // TODO(b/260573124): Add correct enforcing admin when permission changes are
- // merged, and don't forget to handle delegates! Enterprise admins assume
- // component name isn't null.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()),
+ enforcingAdmin,
new IntegerPolicyValue(grantState),
caller.getUserId());
// TODO: update javadoc to reflect that callback no longer return success/failure
callback.sendResult(Bundle.EMPTY);
} else {
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+ || isFinancedDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_PERMISSION_GRANT)));
synchronized (getLockObject()) {
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -15562,10 +16085,16 @@
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
- || isFinancedDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
+ if (isPermissionCheckFlagEnabled()) {
+ enforceCanQuery(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, caller.getPackageName(),
+ caller.getUserId());
+ } else {
+ Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+ || isFinancedDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller,
+ DELEGATION_PERMISSION_GRANT)));
+ }
synchronized (getLockObject()) {
if (isFinancedDeviceOwner(caller)) {
@@ -15981,14 +16510,29 @@
}
@Override
- public void setShortSupportMessage(@NonNull ComponentName who, CharSequence message) {
+ public void setShortSupportMessage(@Nullable ComponentName who, String callerPackageName,
+ CharSequence message) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ ActiveAdmin admin;
+
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ caller.getPackageName(),
+ caller.getUserId());
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ synchronized (getLockObject()) {
+ admin = getActiveAdminForUidLocked(who, caller.getUid());
+ }
+ }
+
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who, caller.getUid());
if (!TextUtils.equals(admin.shortSupportMessage, message)) {
admin.shortSupportMessage = message;
saveSettingsLocked(caller.getUserId());
@@ -15996,21 +16540,33 @@
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_SHORT_SUPPORT_MESSAGE)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.write();
}
@Override
- public CharSequence getShortSupportMessage(@NonNull ComponentName who) {
+ public CharSequence getShortSupportMessage(@Nullable ComponentName who,
+ String callerPackageName) {
if (!mHasFeature) {
return null;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who, caller.getUid());
- return admin.shortSupportMessage;
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ ActiveAdmin admin;
+
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ caller.getPackageName(),
+ caller.getUserId());
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ synchronized (getLockObject()) {
+ admin = getActiveAdminForUidLocked(who, caller.getUid());
+ }
}
+ return admin.shortSupportMessage;
}
@Override
@@ -16162,7 +16718,8 @@
}
@Override
- public void setOrganizationName(@Nullable ComponentName who, CharSequence text) {
+ public void setOrganizationName(@Nullable ComponentName who, String callerPackageName,
+ CharSequence text) {
if (!mHasFeature) {
return;
}
@@ -16193,12 +16750,12 @@
}
@Override
- public CharSequence getOrganizationName(@Nullable ComponentName who) {
+ public CharSequence getOrganizationName(@Nullable ComponentName who, String callerPackageName) {
if (!mHasFeature) {
return null;
}
CallerIdentity caller = getCallerIdentity(who);
- ActiveAdmin admin = null;
+ ActiveAdmin admin;
if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
@@ -16599,7 +17156,8 @@
synchronized (getLockObject()) {
if (isPermissionCheckFlagEnabled()) {
// TODO: add support for DELEGATION_SECURITY_LOGGING
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
if (admin != null) {
Preconditions.checkCallAuthorization(
@@ -16640,7 +17198,8 @@
if (!isSystemUid(getCallerIdentity())) {
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ caller.getPackageName(), UserHandle.USER_ALL);
} else {
if (admin != null) {
Preconditions.checkCallAuthorization(
@@ -16678,7 +17237,8 @@
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
// TODO: Restore the "affiliated users" check
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
if (admin != null) {
Preconditions.checkCallAuthorization(
@@ -16729,7 +17289,8 @@
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
// TODO: Restore the "affiliated users" check
- enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
if (admin != null) {
Preconditions.checkCallAuthorization(
@@ -17588,21 +18149,23 @@
}
@Override
- public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
+ public boolean setResetPasswordToken(ComponentName admin, String callerPackageName,
+ byte[] token) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return false;
}
if (token == null || token.length < 32) {
throw new IllegalArgumentException("token must be at least 32-byte long");
}
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
final int userId = caller.getUserId();
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- admin, userId);
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ caller.getPackageName(),
+ UserHandle.USER_ALL);
Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.RESET_PASSWORD_TOKEN,
enforcingAdmin,
@@ -17619,6 +18182,9 @@
userId);
return true;
} else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userId);
policy.mPasswordTokenHandle = addEscrowToken(
@@ -17645,19 +18211,20 @@
}
@Override
- public boolean clearResetPasswordToken(ComponentName admin) {
+ public boolean clearResetPasswordToken(ComponentName admin, String callerPackageName) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return false;
}
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
final int userId = caller.getUserId();
boolean result = false;
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- admin, userId);
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ caller.getPackageName(),
+ UserHandle.USER_ALL);
Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.RESET_PASSWORD_TOKEN,
enforcingAdmin,
@@ -17670,6 +18237,9 @@
userId);
}
} else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userId);
if (policy.mPasswordTokenHandle != 0) {
@@ -17683,19 +18253,19 @@
}
@Override
- public boolean isResetPasswordTokenActive(ComponentName admin) {
+ public boolean isResetPasswordTokenActive(ComponentName admin, String callerPackageName) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return false;
}
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
-
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
int userId = caller.getUserId();
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- admin, userId);
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ caller.getPackageName(),
+ UserHandle.USER_ALL);
Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.RESET_PASSWORD_TOKEN,
enforcingAdmin,
@@ -17703,6 +18273,9 @@
return isResetPasswordTokenActiveForUserLocked(
currentTokenHandle == null ? 0 : currentTokenHandle, userId);
} else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userId);
return isResetPasswordTokenActiveForUserLocked(policy.mPasswordTokenHandle, userId);
@@ -17720,24 +18293,26 @@
}
@Override
- public boolean resetPasswordWithToken(ComponentName admin, String passwordOrNull, byte[] token,
+ public boolean resetPasswordWithToken(ComponentName admin, String callerPackageName,
+ String passwordOrNull, byte[] token,
int flags) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return false;
}
Objects.requireNonNull(token);
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
int userId = caller.getUserId();
boolean result = false;
final String password = passwordOrNull != null ? passwordOrNull : "";
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
- EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
- admin, userId);
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ admin,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ caller.getPackageName(),
+ UserHandle.USER_ALL);
Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
PolicyDefinition.RESET_PASSWORD_TOKEN,
enforcingAdmin,
@@ -17748,6 +18323,9 @@
Slogf.w(LOG_TAG, "No saved token handle");
}
} else {
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userId);
if (policy.mPasswordTokenHandle != 0) {
@@ -18430,7 +19008,8 @@
final CallerIdentity caller = getCallerIdentity(admin, callerPackageName);
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
@@ -18827,11 +19406,11 @@
for (int i = 0; i < exemptions.length; i++) {
appOpExemptions[i] = APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.get(exemptions[i]);
}
-// DevicePolicyEventLogger
-// .createEvent(DevicePolicyEnums.SET_APPLICATION_EXEMPTIONS)
-// .setAdmin(caller.getPackageName())
-// .setStrings(packageName, appOpExemptions)
-// .write();
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_APPLICATION_EXEMPTIONS)
+ .setAdmin(caller.getPackageName())
+ .setStrings(packageName, appOpExemptions)
+ .write();
}
@Override
@@ -18901,28 +19480,34 @@
}
@Override
- public void setUserControlDisabledPackages(ComponentName who, List<String> packages) {
- Objects.requireNonNull(who, "ComponentName is null");
+ public void setUserControlDisabledPackages(ComponentName who, String callerPackageName,
+ List<String> packages) {
Objects.requireNonNull(packages, "packages is null");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
- || isFinancedDeviceOwner(caller));
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
checkCanExecuteOrThrowUnsafe(
DevicePolicyManager.OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES);
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ caller.getPackageName(),
+ caller.getUserId());
Binder.withCleanCallingIdentity(() -> {
if (packages.isEmpty()) {
- removeUserControlDisabledPackages(caller);
+ removeUserControlDisabledPackages(caller, enforcingAdmin);
} else {
- addUserControlDisabledPackages(caller, new HashSet<>(packages));
+ addUserControlDisabledPackages(caller, enforcingAdmin, new HashSet<>(packages));
}
});
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller) || isFinancedDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
- if (!Objects.equals(owner.protectedPackages, packages)) {
- owner.protectedPackages = packages.isEmpty() ? null : packages;
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
+ if (!Objects.equals(admin.protectedPackages, packages)) {
+ admin.protectedPackages = packages.isEmpty() ? null : packages;
saveSettingsLocked(caller.getUserId());
pushUserControlDisabledPackagesLocked(caller.getUserId());
}
@@ -18931,47 +19516,37 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.setStrings(packages.toArray(new String[packages.size()]))
.write();
}
- private void addUserControlDisabledPackages(CallerIdentity caller, Set<String> packages) {
+ private void addUserControlDisabledPackages(CallerIdentity caller,
+ EnforcingAdmin enforcingAdmin, Set<String> packages) {
if (isCallerDeviceOwner(caller)) {
mDevicePolicyEngine.setGlobalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
- // TODO(b/260573124): add correct enforcing admin when permission changes are
- // merged.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()),
+ enforcingAdmin,
new StringSetPolicyValue(packages));
} else {
mDevicePolicyEngine.setLocalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
- // TODO(b/260573124): add correct enforcing admin when permission changes are
- // merged.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()),
+ enforcingAdmin,
new StringSetPolicyValue(packages),
caller.getUserId());
}
}
- private void removeUserControlDisabledPackages(CallerIdentity caller) {
+ private void removeUserControlDisabledPackages(CallerIdentity caller,
+ EnforcingAdmin enforcingAdmin) {
if (isCallerDeviceOwner(caller)) {
mDevicePolicyEngine.removeGlobalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
- // TODO(b/260573124): add correct enforcing admin when permission changes are
- // merged.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()));
+ enforcingAdmin);
} else {
mDevicePolicyEngine.removeLocalPolicy(
PolicyDefinition.USER_CONTROLLED_DISABLED_PACKAGES,
- // TODO(b/260573124): add correct enforcing admin when permission changes are
- // merged.
- EnforcingAdmin.createEnterpriseEnforcingAdmin(
- caller.getComponentName(), caller.getUserId()),
+ enforcingAdmin,
caller.getUserId());
}
}
@@ -18983,14 +19558,15 @@
}
@Override
- public List<String> getUserControlDisabledPackages(ComponentName who) {
- Objects.requireNonNull(who, "ComponentName is null");
-
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
- || isFinancedDeviceOwner(caller));
+ public List<String> getUserControlDisabledPackages(ComponentName who,
+ String callerPackageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ enforceCanQuery(
+ caller.getPackageName(),
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ caller.getUserId());
// This retrieves the policy for the calling user only, DOs for example can't know
// what's enforced globally or on another user.
Set<String> packages = mDevicePolicyEngine.getResolvedPolicy(
@@ -18998,30 +19574,47 @@
caller.getUserId());
return packages == null ? Collections.emptyList() : packages.stream().toList();
} else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller) || isFinancedDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin deviceOwner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
- return deviceOwner.protectedPackages != null
- ? deviceOwner.protectedPackages : Collections.emptyList();
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
+ return admin.protectedPackages != null
+ ? admin.protectedPackages : Collections.emptyList();
}
}
}
@Override
- public void setCommonCriteriaModeEnabled(ComponentName who, boolean enabled) {
- Objects.requireNonNull(who, "Admin component name must be provided");
- final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
- "Common Criteria mode can only be controlled by a device owner or "
- + "a profile owner on an organization-owned device.");
+ public void setCommonCriteriaModeEnabled(ComponentName who, String callerPackageName,
+ boolean enabled) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final ActiveAdmin admin;
+
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ caller.getPackageName(),
+ caller.getUserId());
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
+ "Common Criteria mode can only be controlled by a device owner or "
+ + "a profile owner on an organization-owned device.");
+ synchronized (getLockObject()) {
+ admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
+ }
+ }
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
admin.mCommonCriteriaMode = enabled;
saveSettingsLocked(caller.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_COMMON_CRITERIA_MODE)
- .setAdmin(who)
+ .setAdmin(caller.getPackageName())
.setBoolean(enabled)
.write();
}
@@ -19040,6 +19633,7 @@
return admin.mCommonCriteriaMode;
}
}
+
// Return aggregated state if caller is not admin (who == null).
synchronized (getLockObject()) {
// Only DO or COPE PO can turn on CC mode, so take a shortcut here and only look at
@@ -19863,10 +20457,14 @@
});
}
- private boolean isDevicePolicyManagementRoleHolder(CallerIdentity caller) {
+ private boolean isCallerDevicePolicyManagementRoleHolder(CallerIdentity caller) {
+ int callerUid = caller.getUid();
String devicePolicyManagementRoleHolderPackageName =
getDevicePolicyManagementRoleHolderPackageName(mContext);
- return caller.getPackageName().equals(devicePolicyManagementRoleHolderPackageName);
+ int roleHolderUid = mInjector.getPackageManagerInternal().getPackageUid(
+ devicePolicyManagementRoleHolderPackageName, 0, caller.getUserId());
+
+ return callerUid == roleHolderUid;
}
private void resetInteractAcrossProfilesAppOps(@UserIdInt int userId) {
@@ -20646,7 +21244,8 @@
public WifiSsidPolicy getWifiSsidPolicy() {
final CallerIdentity caller = getCallerIdentity();
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_WIFI, caller.getUserId());
+ enforcePermission(MANAGE_DEVICE_POLICY_WIFI, /*callerPackageName=*/ null,
+ caller.getUserId());
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
@@ -21079,15 +21678,77 @@
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD);
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_VPN,
+ MANAGE_DEVICE_POLICY_WALLPAPER,
+ MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_WINDOWS,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ );
private static final List<String> FINANCED_DEVICE_OWNER_PERMISSIONS = List.of(
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD);
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_TIME);
private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
List.of(
MANAGE_DEVICE_POLICY_ACROSS_USERS,
@@ -21096,38 +21757,142 @@
SET_TIME_ZONE,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD);
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
+ MANAGE_DEVICE_POLICY_MTE,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_LOCK,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_VPN,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
+ MANAGE_DEVICE_POLICY_MTE,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_LOCK,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_CERTIFICATES);
private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS = List.of(
SET_TIME,
SET_TIME_ZONE,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD);
- private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
MANAGE_DEVICE_POLICY_WIPE_DATA,
MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD);
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_WINDOWS,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS);
+ private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of(
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_LOCK,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_VPN,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ );
private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
{
@@ -21139,8 +21904,18 @@
DPC_PERMISSIONS.put(PROFILE_OWNER, PROFILE_OWNER_PERMISSIONS);
}
+ // Map of permission Active admin DEVICE_POLICY.
//TODO(b/254253251) Fill this map in as new permissions are added for policies.
private static final HashMap<String, Integer> ACTIVE_ADMIN_POLICIES = new HashMap<>();
+ {
+ //Any ActiveAdmin is able to call the support message APIs without certain policies.
+ ACTIVE_ADMIN_POLICIES.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, null);
+ }
+ //Map of Permission to Delegate Scope.
+ private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
+ {
+ DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT);
+ }
private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
new HashMap<>();
@@ -21157,6 +21932,7 @@
// mte is intrinsically global so there is no cross-user permission
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MTE, null);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_STATUS_BAR, null);
// Organisation identity policy will involve data of other organisations on the device and
// therefore the FULL cross-user permission is required.
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
@@ -21175,6 +21951,94 @@
MANAGE_DEVICE_POLICY_LOCK, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(
MANAGE_DEVICE_POLICY_KEYGUARD, MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+ // Granting runtime permissions can grant applications significant powers therefore the FULL
+ // cross-user permission is required.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_VPN,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WALLPAPER,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WINDOWS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
}
/**
@@ -21182,8 +22046,10 @@
* specific user.
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
- * Returns the {@link ActiveAdmin} of the caller.
+ * Returns an {@link EnforcingAdmin} for the caller.
*
+ * @param admin the component name of the admin.
+ * @param callerPackageName The package name of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
@@ -21191,7 +22057,7 @@
*/
private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
String permission, String callerPackageName, int targetUserId) {
- enforcePermission(permission, targetUserId);
+ enforcePermission(permission, callerPackageName, targetUserId);
return getEnforcingAdminForCaller(admin, callerPackageName);
}
@@ -21208,7 +22074,7 @@
*/
private EnforcingAdmin enforceCanQueryAndGetEnforcingAdmin(@Nullable ComponentName admin,
String permission, String callerPackageName, int targetUserId) {
- enforceCanQuery(permission, targetUserId);
+ enforceCanQuery(permission, callerPackageName, targetUserId);
return getEnforcingAdminForCaller(admin, callerPackageName);
}
@@ -21223,14 +22089,15 @@
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
*
+ * @param callerPackageName The package name of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associated cross-user permission if the caller's user is different to the target user.
*/
- private void enforcePermission(String permission, int targetUserId)
+ private void enforcePermission(String permission, String callerPackageName, int targetUserId)
throws SecurityException {
- if (!hasPermission(permission, targetUserId)) {
+ if (!hasPermission(permission, callerPackageName, targetUserId)) {
throw new SecurityException("Caller does not have the required permissions for "
+ "this user. Permissions required: {"
+ permission
@@ -21246,31 +22113,36 @@
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
*
+ * @param callerPackageName The package name of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associated cross-user permission if the caller's user is different to the target user
* and if the user has not been granted {@link QUERY_ADMIN_POLICY}.
*/
- private void enforceCanQuery(String permission, int targetUserId) throws SecurityException {
- if (hasPermission(QUERY_ADMIN_POLICY)) {
+ private void enforceCanQuery(String permission, String callerPackageName, int targetUserId)
+ throws SecurityException {
+ if (hasPermission(QUERY_ADMIN_POLICY, callerPackageName)) {
return;
}
- enforcePermission(permission, targetUserId);
+ enforcePermission(permission, callerPackageName, targetUserId);
}
/**
* Return whether the calling process has been granted permission to apply a device policy on
* a specific user.
*
+ * @param callerPackageName The package name of the calling application.
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
*/
- private boolean hasPermission(String permission, int targetUserId) {
- boolean hasPermissionOnOwnUser = hasPermission(permission);
+ private boolean hasPermission(String permission, String callerPackageName, int targetUserId) {
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ boolean hasPermissionOnOwnUser = hasPermission(permission, callerPackageName);
boolean hasPermissionOnTargetUser = true;
- if (hasPermissionOnOwnUser & getCallerIdentity().getUserId() != targetUserId) {
- hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission));
+ if (hasPermissionOnOwnUser & caller.getUserId() != targetUserId) {
+ hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission),
+ callerPackageName);
}
return hasPermissionOnOwnUser && hasPermissionOnTargetUser;
}
@@ -21278,14 +22150,16 @@
/**
* Return whether the calling process has been granted the given permission.
*
+ * @param callerPackageName The package name of the calling application.
* @param permission The name of the permission being checked.
*/
- private boolean hasPermission(String permission) {
+ private boolean hasPermission(String permission, @NonNull String callerPackageName) {
+ Objects.requireNonNull(callerPackageName, "callerPackageName is null");
if (permission == null) {
return true;
}
- CallerIdentity caller = getCallerIdentity();
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
// Check if the caller holds the permission
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
@@ -21309,14 +22183,23 @@
return DPC_PERMISSIONS.get(PROFILE_OWNER).contains(permission);
}
// Check the permission for the role-holder
- if (isDevicePolicyManagementRoleHolder(caller)) {
+ if (isCallerDevicePolicyManagementRoleHolder(caller)) {
return anyDpcHasPermission(permission, mContext.getUserId());
}
+ if (DELEGATE_SCOPES.containsKey(permission)) {
+ return isCallerDelegate(caller, DELEGATE_SCOPES.get(permission));
+ }
// Check if the caller is an active admin that uses a certain policy.
if (ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
try {
- return getActiveAdminForCallerLocked(
- null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
+ if (ACTIVE_ADMIN_POLICIES.get(permission) != null) {
+ return getActiveAdminForCallerLocked(
+ null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
+ } else {
+ // If the permission maps to no policy (null) this means that any active admin
+ // has permission.
+ return getActiveAdminForUidLocked(null, caller.getUid()) != null;
+ }
} catch (SecurityException e) {
// A security exception means there is not an active admin with permission and
// therefore
@@ -21356,13 +22239,20 @@
String callerPackageName) {
CallerIdentity caller = getCallerIdentity(callerPackageName);
int userId = caller.getUserId();
- ActiveAdmin admin = null;
+ ActiveAdmin admin;
synchronized (getLockObject()) {
admin = getActiveAdminUncheckedLocked(who, userId);
}
if (isDeviceOwner(caller) || isProfileOwner(caller)) {
return EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userId, admin);
}
+ if (isCallerDelegate(caller)) {
+ ComponentName profileOwner = mOwners.getProfileOwnerComponent(caller.getUserId());
+ ComponentName dpc = profileOwner != null ? profileOwner :
+ mOwners.getDeviceOwnerComponent();
+ ActiveAdmin dpcAdmin = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
+ return EnforcingAdmin.createEnterpriseEnforcingAdmin(dpc, userId, dpcAdmin);
+ }
if (getActiveAdminUncheckedLocked(who, userId) != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
@@ -21372,6 +22262,11 @@
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
+ private int getAffectedUser(boolean calledOnParent) {
+ int callingUserId = mInjector.userHandleGetCallingUserId();
+ return calledOnParent ? getProfileParentId(callingUserId) : callingUserId;
+ }
+
private boolean isPermissionCheckFlagEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_DEVICE_POLICY_MANAGER,
@@ -21428,7 +22323,8 @@
}
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_MTE, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
@@ -21468,7 +22364,8 @@
public int getMtePolicy(String callerPackageName) {
final CallerIdentity caller = getCallerIdentity(callerPackageName);
if (isPermissionCheckFlagEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_MTE, UserHandle.USER_ALL);
+ enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(),
+ UserHandle.USER_ALL);
} else {
Preconditions.checkCallAuthorization(
isDefaultDeviceOwner(caller)
@@ -21938,7 +22835,8 @@
}
private boolean isDevicePolicyEngineEnabled() {
- return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
+ return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence()
+ && isPermissionCheckFlagEnabled();
}
private boolean isDevicePolicyEngineFlagEnabled() {
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 8ceac79..de7dc3b 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -1394,6 +1394,22 @@
return false
}
+ private fun addAllowlistedRestrictedPermissionsUnchecked(
+ androidPackage: AndroidPackage,
+ appId: Int,
+ permissionNames: List<String>,
+ userId: Int
+ ) {
+ val newPermissionNames = getAllowlistedRestrictedPermissionsUnchecked(appId,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId
+ )?.let {
+ IndexedSet(permissionNames).apply { this += it }.toList()
+ } ?: permissionNames
+
+ setAllowlistedRestrictedPermissionsUnchecked(androidPackage, appId, newPermissionNames,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId)
+ }
+
override fun removeAllowlistedRestrictedPermission(
packageName: String,
permissionName: String,
@@ -1445,7 +1461,7 @@
private fun setAllowlistedRestrictedPermissions(
packageName: String,
- allowlistedPermissions: List<String>,
+ permissionNames: List<String>,
allowlistedFlags: Int,
userId: Int,
isAddingPermission: Boolean
@@ -1480,7 +1496,7 @@
}
setAllowlistedRestrictedPermissionsUnchecked(
- androidPackage, packageState.appId, allowlistedPermissions, allowlistedFlags, userId
+ androidPackage, packageState.appId, permissionNames, allowlistedFlags, userId
)
return true
@@ -1493,7 +1509,7 @@
private fun setAllowlistedRestrictedPermissionsUnchecked(
androidPackage: AndroidPackage,
appId: Int,
- allowlistedPermissions: List<String>,
+ permissionNames: List<String>,
allowlistedFlags: Int,
userId: Int
) {
@@ -1522,7 +1538,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> {
mask = mask or PermissionFlags.SYSTEM_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.SYSTEM_EXEMPT
} else {
newFlags andInv PermissionFlags.SYSTEM_EXEMPT
@@ -1531,7 +1547,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> {
mask = mask or PermissionFlags.UPGRADE_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.UPGRADE_EXEMPT
} else {
newFlags andInv PermissionFlags.UPGRADE_EXEMPT
@@ -1540,7 +1556,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> {
mask = mask or PermissionFlags.INSTALLER_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.INSTALLER_EXEMPT
} else {
newFlags andInv PermissionFlags.INSTALLER_EXEMPT
@@ -1856,10 +1872,15 @@
@Suppress("NAME_SHADOWING")
userIds.forEach { userId ->
service.onPackageInstalled(androidPackage.packageName, userId)
+ }
+
+ @Suppress("NAME_SHADOWING")
+ userIds.forEach { userId ->
// TODO: Remove when this callback receives packageState directly.
val packageState =
packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
- // TODO: Add allowlisting
+ addAllowlistedRestrictedPermissionsUnchecked(androidPackage, packageState.appId,
+ params.allowlistedRestrictedPermissions, userId)
setRequestedPermissionStates(packageState, userId, params.permissionStates)
}
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index 59551a3..5a7b37a 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -962,7 +962,7 @@
if (packageState.packageName == PLATFORM_PACKAGE_NAME) {
return true
}
- if (!packageState.isPrivileged) {
+ if (!(packageState.isSystem && packageState.isPrivileged)) {
return true
}
if (permission.packageName !in newState.systemState.privilegedPermissionAllowlistPackages) {
diff --git a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
index 62dbd89..9f0e2f5 100644
--- a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
+++ b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
@@ -16,12 +16,14 @@
package com.android.server.restrictions;
+import android.annotation.UserIdInt;
import android.app.AppGlobals;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.IRestrictionsManager;
+import android.content.Intent;
import android.content.RestrictionsManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
@@ -35,6 +37,9 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemService;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* SystemService wrapper for the RestrictionsManager implementation. Publishes the
* Context.RESTRICTIONS_SERVICE.
@@ -60,19 +65,31 @@
final Context mContext;
private final IUserManager mUm;
private final IDevicePolicyManager mDpm;
+ private final DevicePolicyManagerInternal mDpmInternal;
public RestrictionsManagerImpl(Context context) {
mContext = context;
mUm = (IUserManager) getBinderService(Context.USER_SERVICE);
mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE);
+ mDpmInternal = getLocalService(DevicePolicyManagerInternal.class);
}
@Override
+ @Deprecated
public Bundle getApplicationRestrictions(String packageName) throws RemoteException {
return mUm.getApplicationRestrictions(packageName);
}
@Override
+ public List<Bundle> getApplicationRestrictionsPerAdminForUser(
+ @UserIdInt int userId, String packageName) throws RemoteException {
+ if (mDpmInternal != null) {
+ return mDpmInternal.getApplicationRestrictionsPerAdminForUser(packageName, userId);
+ }
+ return new ArrayList<>();
+ }
+
+ @Override
public boolean hasRestrictionsProvider() throws RemoteException {
int userHandle = UserHandle.getCallingUserId();
if (mDpm != null) {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index e2f56ba..94ee0a8 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -1584,11 +1584,7 @@
@Test
public void testConstructor_withNullContext_throws() throws Exception {
expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- /* context */ null,
- new SparseArray<>()));
+ NullPointerException.class, () -> new BackupManagerService(/* context */ null));
}
/** Test that the constructor does not create {@link UserBackupManagerService} instances. */
@@ -1616,18 +1612,6 @@
verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
}
- /** testOnUnlockUser_forwards */
- @Test
- public void testOnUnlockUser_forwards() {
- BackupManagerService backupManagerService = mock(BackupManagerService.class);
- BackupManagerService.Lifecycle lifecycle =
- new BackupManagerService.Lifecycle(mContext, backupManagerService);
-
- lifecycle.onUserUnlocking(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
-
- verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
- }
-
/** testOnStopUser_forwards */
@Test
public void testOnStopUser_forwards() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 2583f44..bcd69fda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -875,7 +875,7 @@
@Test
public void testLightStepIdleStateLocked_InvalidStates() {
mDeviceIdleController.becomeActiveLocked("testing", 0);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
// stepLightIdleStateLocked doesn't handle the ACTIVE case, so the state
// should stay as ACTIVE.
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
@@ -888,7 +888,7 @@
@Test
public void testLightStepIdleStateLocked_Overriden() {
enterLightState(LIGHT_STATE_OVERRIDE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
}
@@ -906,18 +906,18 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -934,18 +934,18 @@
mDeviceIdleController.setJobsActive(true);
mDeviceIdleController.setAlarmsActive(true);
mDeviceIdleController.setActiveIdleOpsForTest(1);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -963,24 +963,24 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -997,83 +997,24 @@
mDeviceIdleController.setJobsActive(true);
mDeviceIdleController.setAlarmsActive(true);
mDeviceIdleController.setActiveIdleOpsForTest(1);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
- verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- }
-
- @Test
- public void testLightStepIdleStateSkippedAlarms() {
- setNetworkConnected(true);
- mDeviceIdleController.setJobsActive(false);
- mDeviceIdleController.setAlarmsActive(false);
- mDeviceIdleController.setActiveIdleOpsForTest(0);
-
- final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor
- .forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
- eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
- doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
- eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
-
- // Set state to INACTIVE.
- mDeviceIdleController.becomeActiveLocked("testing", 0);
- setChargingOn(false);
- setScreenOn(false);
- verifyLightStateConditions(LIGHT_STATE_INACTIVE);
-
- final AlarmManager.OnAlarmListener progressionListener =
- alarmListenerCaptor.getAllValues().get(0);
- final AlarmManager.OnAlarmListener maintenanceListener =
- alarmListenerCaptor.getAllValues().get(1);
-
- // Set things to make it look like the INACTIVE -> IDLE alarm didn't fire and the
- // MAINTENANCE alarm just fired.
- mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
- // If the non-wakeup alarm doesn't fire in a timely manner, we would see both fire at the
- // same time.
- progressionListener.onAlarm();
- verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- maintenanceListener.onAlarm();
- verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
-
- assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
-
- // MAINTENANCE->IDLE alarm goes off at correct time.
- mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
- progressionListener.onAlarm();
- verifyLightStateConditions(LIGHT_STATE_IDLE);
-
- // Go back to MAINTENANCE
- mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
- maintenanceListener.onAlarm();
- verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
-
- assertTrue(mInjector.nowElapsed < mDeviceIdleController.getNextLightAlarmTimeForTesting());
- assertTrue(mInjector.nowElapsed
- < mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting());
-
- // MAINTENANCE->IDLE alarm is delayed until IDLE->MAINTENANCE alarm goes off.
- mInjector.nowElapsed = mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
- progressionListener.onAlarm();
- verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
- maintenanceListener.onAlarm();
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
}
@@ -1097,8 +1038,6 @@
.forClass(AlarmManager.OnAlarmListener.class);
doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
- doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
- eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any());
// Set state to INACTIVE.
mDeviceIdleController.becomeActiveLocked("testing", 0);
@@ -1109,23 +1048,16 @@
final long idleAfterInactiveExpiryTime =
mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
alarmManagerInOrder.verify(mAlarmManager).setWindow(
- eq(AlarmManager.ELAPSED_REALTIME),
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(idleAfterInactiveExpiryTime),
anyLong(), anyString(), any(), any(Handler.class));
- // Maintenance alarm
- alarmManagerInOrder.verify(mAlarmManager).setWindow(
- eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
- eq(idleAfterInactiveExpiryTime + idlingTimeMs),
- anyLong(), anyString(), any(), any(Handler.class));
- final AlarmManager.OnAlarmListener progressionListener =
+ final AlarmManager.OnAlarmListener alarmListener =
alarmListenerCaptor.getAllValues().get(0);
- final AlarmManager.OnAlarmListener maintenanceListener =
- alarmListenerCaptor.getAllValues().get(1);
// INACTIVE -> IDLE alarm
mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
- progressionListener.onAlarm();
+ alarmListener.onAlarm();
verifyLightStateConditions(LIGHT_STATE_IDLE);
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
@@ -1134,26 +1066,20 @@
for (int i = 0; i < 2; ++i) {
// IDLE->MAINTENANCE alarm
- mInjector.nowElapsed =
- mDeviceIdleController.getNextLightMaintenanceAlarmTimeForTesting();
- maintenanceListener.onAlarm();
+ mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
+ alarmListener.onAlarm();
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;
idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR;
// Set MAINTENANCE->IDLE
alarmManagerInOrder.verify(mAlarmManager).setWindow(
- eq(AlarmManager.ELAPSED_REALTIME),
- eq(maintenanceExpiryTime),
- anyLong(), anyString(), any(), any(Handler.class));
- // Set IDLE->MAINTENANCE
- alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
- eq(maintenanceExpiryTime + idlingTimeMs),
+ eq(maintenanceExpiryTime),
anyLong(), anyString(), any(), any(Handler.class));
// MAINTENANCE->IDLE alarm
mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
- progressionListener.onAlarm();
+ alarmListener.onAlarm();
verifyLightStateConditions(LIGHT_STATE_IDLE);
// Set IDLE->MAINTENANCE again
alarmManagerInOrder.verify(mAlarmManager).setWindow(
@@ -1180,37 +1106,45 @@
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
// No active ops means INACTIVE should go straight to IDLE.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
- longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT));
+ inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
+ eq(true));
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
- longThat(l -> l == mConstants.FLEX_TIME_SHORT));
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT),
+ eq(true));
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
+ eq(true));
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
- longThat(l -> l == mConstants.FLEX_TIME_SHORT));
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT),
+ eq(true));
// Test that motion doesn't reset the idle timeout.
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
- inOrder.verify(mDeviceIdleController).scheduleLightMaintenanceAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX),
+ eq(true));
}
///////////////// EXIT conditions ///////////////////
@@ -2230,7 +2164,7 @@
while (mDeviceIdleController.getLightState() != lightState) {
// Stepping through each state ensures that the proper features are turned
// on/off.
- mDeviceIdleController.stepLightIdleStateLocked("testing", true);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
count++;
if (count > 10) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
index cd9d8a9..b203cf6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -37,7 +37,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-
import android.Manifest;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
@@ -54,13 +53,13 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
-import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.SystemService;
import com.android.server.backup.utils.RandomAccessFileUtils;
import org.junit.After;
@@ -104,8 +103,8 @@
private FileDescriptor mFileDescriptorStub = new FileDescriptor();
private BackupManagerServiceTestable mService;
+ private BackupManagerService.Lifecycle mServiceLifecycle;
private static File sTestDir;
- private SparseArray<UserBackupManagerService> mUserServices;
private MockitoSession mSession;
@Before
@@ -125,8 +124,6 @@
mUserId = UserHandle.USER_SYSTEM;
- mUserServices = new SparseArray<>();
-
when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
when(mUserManagerMock.getUserInfo(NON_SYSTEM_USER)).thenReturn(mUserInfoMock);
// Null main user means there is no main user on the device.
@@ -142,8 +139,6 @@
when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE))
.thenReturn(mock(JobScheduler.class));
- mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
- simulateUserUnlocked(UserHandle.USER_SYSTEM);
}
@After
@@ -154,21 +149,20 @@
@Test
public void onUnlockUser_startsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
ConditionVariable unlocked = new ConditionVariable(false);
- mService.onUnlockUser(NON_SYSTEM_USER);
- mService.getBackupHandler().post(unlocked::open);
- unlocked.block();
+ simulateUserUnlocked(NON_SYSTEM_USER);
assertNotNull(mService.getUserService(NON_SYSTEM_USER));
}
@Test
public void startServiceForUser_backupDisabledGlobally_doesNotStartUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerServiceTestable service =
- new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+ BackupManagerServiceTestable service = new BackupManagerServiceTestable(mContextMock);
service.startServiceForUser(UserHandle.USER_SYSTEM);
@@ -177,6 +171,7 @@
@Test
public void startServiceForUser_backupNotActiveForUser_doesNotStartUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
mService.startServiceForUser(UserHandle.USER_SYSTEM);
@@ -186,7 +181,8 @@
@Test
public void startServiceForUser_backupEnabledGloballyAndActiveForUser_startsUserService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
+
mService.startServiceForUser(NON_SYSTEM_USER);
assertNotNull(mService.getUserService(NON_SYSTEM_USER));
@@ -194,9 +190,9 @@
@Test
public void isBackupServiceActive_backupDisabledGlobally_returnFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerService service =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerService service = new BackupManagerServiceTestable(mContextMock);
service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
assertFalse(service.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -204,6 +200,7 @@
@Test
public void isBackupServiceActive_systemUser_isDefault_deactivated_returnsFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
// If there's no 'main' user on the device, the default user is the system user.
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -212,20 +209,23 @@
@Test
public void isBackupServiceActive_systemUser_isNotDefault_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ createBackupManagerServiceAndUnlockSystemUser();
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
}
@Test
public void isBackupServiceActive_systemUser_isDefault_returnsTrue() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
// If there's no 'main' user on the device, the default user is the system user.
assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
}
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_systemUserDeactivated_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -233,7 +233,7 @@
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_deactivated_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -241,19 +241,24 @@
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_returnsTrue() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ createBackupManagerServiceAndUnlockSystemUser();
+
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
}
@Test
public void isBackupServiceActive_nonSystemUser_isNotDefault_notActivated_returnsFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
// By default non-system non-default users are not activated.
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
}
@Test
public void isBackupServiceActive_nonSystemUser_isNotDefault_activated_returnsTrue() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -261,6 +266,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerSystemUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -270,6 +276,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerRootUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -279,6 +286,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
try {
@@ -290,6 +298,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
@@ -301,6 +310,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerRootUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
@@ -312,6 +322,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
@@ -324,6 +335,7 @@
@Test
public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
doThrow(new SecurityException())
.when(mContextMock)
.enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
@@ -337,6 +349,7 @@
@Test
public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
doThrow(new SecurityException())
.when(mContextMock)
.enforceCallingOrSelfPermission(
@@ -351,9 +364,9 @@
@Test
public void setBackupServiceActive_backupDisabledGlobally_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerServiceTestable service =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerServiceTestable service = new BackupManagerServiceTestable(mContextMock);
service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -362,6 +375,7 @@
@Test
public void setBackupServiceActive_alreadyActive_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -371,6 +385,7 @@
@Test
public void setBackupServiceActive_systemUser_makeActive_deletesSuppressFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -380,6 +395,7 @@
@Test
public void setBackupServiceActive_systemUser_makeNonActive_createsSuppressFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
assertTrue(getFakeSuppressFileForUser(UserHandle.USER_SYSTEM).exists());
@@ -387,6 +403,7 @@
@Test
public void setBackupServiceActive_systemUser_makeNonActive_stopsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
assertTrue(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -396,7 +413,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeActive_createsService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -407,7 +424,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeActive_deletesSuppressFile() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -418,7 +435,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeNonActive_createsSuppressFile() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertTrue(getFakeSuppressFileForUser(NON_SYSTEM_USER).exists());
@@ -426,7 +443,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeNonActive_stopsUserService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER));
@@ -437,6 +454,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
@@ -446,6 +464,8 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_createActivatedFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(getFakeActivatedFileForUser(NON_SYSTEM_USER).exists());
@@ -453,6 +473,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeNonActive_stopsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
@@ -463,6 +484,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_deleteActivatedFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -472,6 +494,7 @@
@Test
public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
+ createBackupManagerServiceAndUnlockSystemUser();
int otherUser = NON_SYSTEM_USER + 1;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -482,6 +505,8 @@
@Test
public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(RandomAccessFileUtils.readBoolean(
@@ -490,6 +515,8 @@
@Test
public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertFalse(RandomAccessFileUtils.readBoolean(
@@ -498,6 +525,8 @@
@Test
public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -508,7 +537,7 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
throws Exception {
- mUserServices.clear();
+ mService = new BackupManagerServiceTestable(mContextMock);
CompletableFuture<Integer> future = new CompletableFuture<>();
ISelectBackupTransportCallback listener =
new ISelectBackupTransportCallback.Stub() {
@@ -531,6 +560,8 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
throws Exception {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
// No crash.
@@ -539,6 +570,8 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow()
throws Exception {
+ createBackupManagerServiceAndUnlockSystemUser();
+
ISelectBackupTransportCallback.Stub listener =
new ISelectBackupTransportCallback.Stub() {
@Override
@@ -558,6 +591,7 @@
@Test
public void dump_callerDoesNotHaveDumpPermission_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mContextMock.checkCallingOrSelfPermission(
Manifest.permission.DUMP)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -570,6 +604,7 @@
@Test
public void dump_callerDoesNotHavePackageUsageStatsPermission_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mContextMock.checkCallingOrSelfPermission(
Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -586,6 +621,7 @@
*/
@Test
public void testDump_systemUserFirst() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
simulateUserUnlocked(NON_SYSTEM_USER);
String[] args = new String[0];
@@ -602,6 +638,7 @@
@Test
public void testGetUserForAncestralSerialNumber_forSystemUser() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserManagerMock.getProfileIds(UserHandle.getCallingUserId(), false))
.thenReturn(new int[]{UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
@@ -614,10 +651,10 @@
@Test
public void testGetUserForAncestralSerialNumber_forNonSystemUser() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserManagerMock.getProfileIds(UserHandle.getCallingUserId(), false))
- .thenReturn(new int[]{UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
+ .thenReturn(new int[] {UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
when(mNonSystemUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
UserHandle user = mService.getUserForAncestralSerialNumber(11L);
@@ -627,9 +664,9 @@
@Test
public void testGetUserForAncestralSerialNumber_whenDisabled() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerService backupManagerService =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerService backupManagerService = new BackupManagerServiceTestable(mContextMock);
when(mSystemUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
@@ -637,18 +674,68 @@
assertThat(user).isNull();
}
+ @Test
+ public void onUserUnlocking_mainUserChanged_firstUnlockAfterReboot_updatesDefaultUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+
+ assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
+ }
+
+ @Test
+ public void onUserUnlocking_mainUserChanged_firstUnlockAfterReboot_doesNotStartForSystemUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+
+ assertFalse(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void onUserUnlocking_mainUserChanged_secondUnlockAfterReboot_doesNotUpdateDefaultUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ createBackupManagerServiceAndUnlockSystemUser();
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(NON_SYSTEM_USER);
+
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+ }
+
+ private void createBackupManagerServiceAndUnlockSystemUser() {
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+ }
+
/**
* The 'default' user is set in the constructor of {@link BackupManagerService} so we need to
* start a new service after mocking the 'main' user.
*/
- private void setMockMainUserAndStartNewBackupManagerService(int userId) {
+ private void setMockMainUserAndCreateBackupManagerService(int userId) {
when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(userId));
- mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
}
private void simulateUserUnlocked(int userId) {
ConditionVariable unlocked = new ConditionVariable(false);
- mService.onUnlockUser(userId);
+ mServiceLifecycle.onUserUnlocking(
+ new SystemService.TargetUser(
+ new UserInfo(userId, /* name= */ "test", /* flags= */ 0)));
mService.getBackupHandler().post(unlocked::open);
unlocked.block();
when(mUserManagerMock.isUserUnlocked(userId)).thenReturn(true);
@@ -672,9 +759,8 @@
static int sCallingUid = -1;
static UserManager sUserManagerMock = null;
- BackupManagerServiceTestable(
- Context context, SparseArray<UserBackupManagerService> userServices) {
- super(context, userServices);
+ BackupManagerServiceTestable(Context context) {
+ super(context);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 2d036fe..88f0c93 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
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.doAnswer;
@@ -114,6 +115,7 @@
null);
private MagnificationScaleProvider mScaleProvider;
private MockContentResolver mResolver;
+ private final MagnificationThumbnail mMockThumbnail = mock(MagnificationThumbnail.class);
private final ArgumentCaptor<MagnificationConfig> mConfigCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
@@ -151,8 +153,14 @@
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
mScaleProvider = new MagnificationScaleProvider(mMockContext);
- mFullScreenMagnificationController = new FullScreenMagnificationController(
- mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
+
+ mFullScreenMagnificationController =
+ new FullScreenMagnificationController(
+ mMockControllerCtx,
+ new Object(),
+ mRequestObserver,
+ mScaleProvider,
+ () -> mMockThumbnail);
}
@After
@@ -191,6 +199,8 @@
verify(mMockWindowManager).setMagnificationCallbacks(eq(DISPLAY_1), eq(null));
assertFalse(mFullScreenMagnificationController.isRegistered(DISPLAY_0));
assertFalse(mFullScreenMagnificationController.isRegistered(DISPLAY_1));
+
+ verify(mMockThumbnail, times(2)).hideThumbNail();
}
@Test
@@ -527,6 +537,8 @@
verify(mRequestObserver).onFullScreenMagnificationChanged(eq(displayId), eq(OTHER_REGION),
mConfigCaptor.capture());
assertConfigEquals(config, mConfigCaptor.getValue());
+
+ verify(mMockThumbnail).setThumbNailBounds(any(), anyFloat(), anyFloat(), anyFloat());
}
@Test
@@ -849,6 +861,9 @@
mMessageCapturingHandler.sendAllMessages();
assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
verifyNoMoreInteractions(mMockWindowManager);
+
+ verify(mMockThumbnail)
+ .updateThumbNail(eq(scale), eq(startCenter.x), eq(startCenter.y));
}
@Test
@@ -1240,6 +1255,7 @@
private void resetMockWindowManager() {
Mockito.reset(mMockWindowManager);
+ Mockito.reset(mMockThumbnail);
initMockWindowManager();
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index a095760..51d3bae 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -163,9 +163,13 @@
when(mockController.newValueAnimator()).thenReturn(new ValueAnimator());
when(mockController.getAnimationDuration()).thenReturn(1000L);
when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true);
- mFullScreenMagnificationController = new FullScreenMagnificationController(mockController,
- new Object(), mMagnificationInfoChangedCallback,
- new MagnificationScaleProvider(mContext)) {
+ mFullScreenMagnificationController = new FullScreenMagnificationController(
+ mockController,
+ new Object(),
+ mMagnificationInfoChangedCallback,
+ new MagnificationScaleProvider(mContext),
+ () -> null
+ ) {
@Override
public boolean magnificationRegionContains(int displayId, float x, float y) {
return true;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index b4a16c2..bbcb376 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -194,8 +194,12 @@
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternal);
mScreenMagnificationController = spy(new FullScreenMagnificationController(
- mControllerCtx, new Object(),
- mScreenMagnificationInfoChangedCallbackDelegate, mScaleProvider));
+ mControllerCtx,
+ new Object(),
+ mScreenMagnificationInfoChangedCallbackDelegate,
+ mScaleProvider,
+ () -> null
+ ));
mScreenMagnificationController.register(TEST_DISPLAY);
mWindowMagnificationManager = spy(new WindowMagnificationManager(mContext, globalLock,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java
new file mode 100644
index 0000000..60c8148
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.accessibility.magnification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.platform.test.annotations.LargeTest;
+import android.testing.TestableContext;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class MagnificationThumbnailTest {
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
+
+ private final WindowManager mMockWindowManager = mock(WindowManager.class);
+ private final Handler mHandler = mContext.getMainThreadHandler();
+
+ private MagnificationThumbnail mMagnificationThumbnail;
+
+ @Before
+ public void setUp() {
+ var metrics = new WindowMetrics(new Rect(), WindowInsets.CONSUMED, 1f);
+ when(mMockWindowManager.getCurrentWindowMetrics()).thenReturn(metrics);
+ mMagnificationThumbnail = new MagnificationThumbnail(
+ mContext,
+ mMockWindowManager,
+ mHandler
+ );
+ }
+
+ @Test
+ public void updateThumbnailShows() {
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2.2f,
+ /* centerX= */ 15,
+ /* centerY= */ 50
+ ));
+ idle();
+
+ verify(mMockWindowManager).addView(eq(mMagnificationThumbnail.mThumbnailLayout), any());
+ assertThat(mMagnificationThumbnail.mThumbnailLayout.getAlpha()).isGreaterThan(0.5f);
+ }
+
+ @Test
+ public void updateThumbnailLingersThenHidesAfterTimeout() throws InterruptedException {
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ // Wait for the linger delay then fade out animation
+ Thread.sleep(2000L);
+ idle();
+
+ verify(mMockWindowManager).removeView(eq(mMagnificationThumbnail.mThumbnailLayout));
+ assertThat(mMagnificationThumbnail.mThumbnailLayout.getAlpha()).isLessThan(0.1f);
+ }
+
+ @Test
+ public void hideThumbnailRemoves() throws InterruptedException {
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail());
+ idle();
+
+ // Wait for the fade out animation
+ Thread.sleep(1100L);
+
+ verify(mMockWindowManager).removeView(eq(mMagnificationThumbnail.mThumbnailLayout));
+ assertThat(mMagnificationThumbnail.mThumbnailLayout.getAlpha()).isLessThan(0.1f);
+ }
+
+ @Test
+ public void hideShowHideShowHideRemoves() throws InterruptedException {
+ runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail());
+ idle();
+
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ // Wait for the fade in animation
+ Thread.sleep(200L);
+
+ runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail());
+ idle();
+
+ runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail(
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail());
+ idle();
+
+
+ // Wait for the fade out animation
+ Thread.sleep(1100L);
+
+ verify(mMockWindowManager).removeView(eq(mMagnificationThumbnail.mThumbnailLayout));
+ assertThat(mMagnificationThumbnail.mThumbnailLayout.getAlpha()).isLessThan(0.1f);
+ }
+
+ @Test
+ public void hideWithoutShowDoesNothing() throws InterruptedException {
+ runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail());
+ idle();
+
+ // Wait for the fade out animation
+ Thread.sleep(1100L);
+
+ verify(mMockWindowManager, never())
+ .addView(eq(mMagnificationThumbnail.mThumbnailLayout), any());
+ verify(mMockWindowManager, never())
+ .removeView(eq(mMagnificationThumbnail.mThumbnailLayout));
+ }
+
+ @Test
+ public void whenHidden_setBoundsDoesNotShow() throws InterruptedException {
+ runOnMainSync(() -> mMagnificationThumbnail.setThumbNailBounds(
+ new Rect(),
+ /* scale= */ 2f,
+ /* centerX= */ 5,
+ /* centerY= */ 10
+ ));
+ idle();
+
+ // Wait for the fade in/out animation
+ Thread.sleep(1100L);
+
+ verify(mMockWindowManager, never())
+ .addView(eq(mMagnificationThumbnail.mThumbnailLayout), any());
+ verify(mMockWindowManager, never())
+ .removeView(eq(mMagnificationThumbnail.mThumbnailLayout));
+ }
+
+ private static void idle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ private static void runOnMainSync(Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3d6e1af..48025ed 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2775,8 +2775,7 @@
// Can't set message for admin in another uid.
{
mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
- assertExpectException(SecurityException.class,
- /* messageRegex= */ "is not owned by uid",
+ assertThrows(SecurityException.class,
() -> dpm.setShortSupportMessage(admin1, "Some text"));
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
diff --git a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
index 454d3f3..9ce80c4 100644
--- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -19,6 +19,9 @@
import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
import static android.os.PowerManager.LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.MATCH_PORT_LOCAL;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_TCP;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_UDP;
import static com.google.common.truth.Truth.assertThat;
@@ -47,9 +50,11 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Binder;
import android.os.IPowerManager;
import android.os.PowerManager;
import android.os.PowerManager.LowPowerStandbyPolicy;
+import android.os.PowerManager.LowPowerStandbyPortDescription;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
@@ -98,6 +103,10 @@
private static final int USER_ID_2 = 10;
private static final LowPowerStandbyPolicy EMPTY_POLICY = new LowPowerStandbyPolicy(
"Test policy", Collections.emptySet(), 0, Collections.emptySet());
+ private static final LowPowerStandbyPortDescription PORT_DESC_1 =
+ new LowPowerStandbyPortDescription(PROTOCOL_UDP, MATCH_PORT_LOCAL, 5353);
+ private static final LowPowerStandbyPortDescription PORT_DESC_2 =
+ new LowPowerStandbyPortDescription(PROTOCOL_TCP, MATCH_PORT_LOCAL, 8008);
private LowPowerStandbyController mController;
private BroadcastInterceptingContext mContextSpy;
@@ -140,6 +149,7 @@
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
when(mDeviceConfigWrapperMock.enableCustomPolicy()).thenReturn(true);
+ when(mDeviceConfigWrapperMock.enableStandbyPorts()).thenReturn(true);
mResourcesSpy = spy(mContextSpy.getResources());
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
when(mResourcesSpy.getBoolean(
@@ -703,6 +713,81 @@
verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
}
+ @Test
+ public void testStandbyPorts_broadcastChangedIfPackageIsExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ Binder token = new Binder();
+ BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mTestLooper.dispatchAll();
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+
+ futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.releaseStandbyPorts(token);
+ mTestLooper.dispatchAll();
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+ }
+
+ @Test
+ public void testStandbyPorts_noBroadcastChangedIfPackageIsNotExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_1));
+ mTestLooper.dispatchAll();
+ futureIntent.assertNotReceived();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_emptyIfDisabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(false);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_emptyIfPackageNotExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG2));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_activeIfPackageExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_2));
+ assertThat(mController.getActiveStandbyPorts()).containsExactly(PORT_DESC_1);
+ }
+
+ @Test
+ public void testActiveStandbyPorts_removedAfterRelease() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+ Binder token = new Binder();
+ mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mController.releaseStandbyPorts(token);
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
private void setInteractive() throws Exception {
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 57f9f18..13c011a 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -30,6 +32,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.thermal.TemperatureThreshold;
import android.hardware.thermal.ThrottlingSeverity;
import android.os.CoolingDevice;
@@ -55,7 +58,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -114,6 +119,7 @@
skinThreshold.type = Temperature.TYPE_SKIN;
skinThreshold.name = "skin1";
skinThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
+ skinThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
for (int i = 0; i < skinThreshold.hotThrottlingThresholds.length; ++i) {
// Sets NONE to 25.0f, SEVERE to 40.0f, and SHUTDOWN to 55.0f
skinThreshold.hotThrottlingThresholds[i] = 25.0f + 5.0f * i;
@@ -124,6 +130,7 @@
cpuThreshold.type = Temperature.TYPE_CPU;
cpuThreshold.name = "cpu";
cpuThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
+ cpuThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
for (int i = 0; i < cpuThreshold.hotThrottlingThresholds.length; ++i) {
if (i == ThrottlingSeverity.SEVERE) {
cpuThreshold.hotThrottlingThresholds[i] = 95.0f;
@@ -189,7 +196,8 @@
@Override
protected void dump(PrintWriter pw, String prefix) {
- return;
+ pw.print(prefix);
+ pw.println("ThermalHAL AIDL 1 connected: yes");
}
}
@@ -496,4 +504,51 @@
return watcher.mSamples.isEmpty();
}
}
+
+ @Test
+ public void testDump() {
+ when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ final StringWriter out = new StringWriter();
+ PrintWriter pw = new PrintWriter(out);
+ mService.dumpInternal(new FileDescriptor(), pw, null);
+ final String dumpStr = out.toString();
+ assertThat(dumpStr).contains("IsStatusOverride: false");
+ assertThat(dumpStr).contains(
+ "ThermalEventListeners:\n"
+ + "\tcallbacks: 2\n"
+ + "\tkilled: false\n"
+ + "\tbroadcasts count: -1");
+ assertThat(dumpStr).contains(
+ "ThermalStatusListeners:\n"
+ + "\tcallbacks: 2\n"
+ + "\tkilled: false\n"
+ + "\tbroadcasts count: -1");
+ assertThat(dumpStr).contains("Thermal Status: 0");
+ assertThat(dumpStr).contains(
+ "Cached temperatures:\n"
+ + "\tTemperature{mValue=0.0, mType=4, mName=usbport, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=2, mName=batt, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=3, mName=skin1, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=3, mName=skin2, mStatus=0}"
+ );
+ assertThat(dumpStr).contains("HAL Ready: true\n"
+ + "HAL connection:\n"
+ + "\tThermalHAL AIDL 1 connected: yes");
+ assertThat(dumpStr).contains("Current temperatures from HAL:\n"
+ + "\tTemperature{mValue=0.0, mType=3, mName=skin1, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=3, mName=skin2, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=2, mName=batt, mStatus=0}\n"
+ + "\tTemperature{mValue=0.0, mType=4, mName=usbport, mStatus=0}\n");
+ assertThat(dumpStr).contains("Current cooling devices from HAL:\n"
+ + "\tCoolingDevice{mValue=0, mType=1, mName=cpu}\n"
+ + "\tCoolingDevice{mValue=0, mType=1, mName=gpu}\n");
+ assertThat(dumpStr).contains("Temperature static thresholds from HAL:\n"
+ + "\tTemperatureThreshold{mType=3, mName=skin1, mHotThrottlingThresholds=[25.0, "
+ + "30.0, 35.0, 40.0, 45.0, 50.0, 55.0], mColdThrottlingThresholds=[0.0, 0.0, 0.0,"
+ + " 0.0, 0.0, 0.0, 0.0]}\n"
+ + "\tTemperatureThreshold{mType=0, mName=cpu, mHotThrottlingThresholds=[NaN, NaN,"
+ + " NaN, 95.0, NaN, NaN, NaN], mColdThrottlingThresholds=[0.0, 0.0, 0.0, 0.0, 0"
+ + ".0, 0.0, 0.0]}");
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 687696a..96ec2b8 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -48,6 +48,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
@@ -73,6 +74,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.google.common.truth.Truth.assertThat;
@@ -82,6 +85,7 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -111,6 +115,7 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -170,6 +175,8 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -203,6 +210,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
@@ -320,6 +328,8 @@
@Mock
private NotificationManager mMockNm;
@Mock
+ private PermissionManager mPermissionManager;
+ @Mock
private DevicePolicyManagerInternal mDevicePolicyManager;
@Mock
@@ -527,7 +537,7 @@
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
mock(TelephonyManager.class),
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
- mTelecomManager, mLogger, mTestFlagResolver);
+ mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager);
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
@@ -604,6 +614,9 @@
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
clearInvocations(mRankingHandler);
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+
+ mTestFlagResolver.setFlagOverride(FSI_FORCE_DEMOTE, false);
+ mTestFlagResolver.setFlagOverride(SHOW_STICKY_HUN_FOR_DENIED_FSI, false);
}
@After
@@ -10111,6 +10124,84 @@
verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
}
+ private void verifyStickyHun(Flag flag, int permissionState, boolean isSticky)
+ throws Exception {
+
+ mTestFlagResolver.setFlagOverride(flag, true);
+
+ when(mPermissionManager.checkPermissionForDataDelivery(
+ eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any()))
+ .thenReturn(permissionState);
+
+ Notification n = new Notification.Builder(mContext, "test")
+ .setFullScreenIntent(mock(PendingIntent.class), true)
+ .build();
+
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid);
+
+ final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
+
+ if (isSticky) {
+ assertNotSame(0, stickyFlag);
+ } else {
+ assertSame(0, stickyFlag);
+ }
+ }
+
+ @Test
+ public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ SHOW_STICKY_HUN_FOR_DENIED_FSI,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_HARD_DENIED,
+ /* isSticky= */ true);
+ }
+
+ @Test
+ public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ SHOW_STICKY_HUN_FOR_DENIED_FSI,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_SOFT_DENIED,
+ /* isSticky= */ true);
+ }
+
+ @Test
+ public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ SHOW_STICKY_HUN_FOR_DENIED_FSI,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_GRANTED,
+ /* isSticky= */ false);
+ }
+
+ @Test
+ public void testFixNotification_flagForceStickyHun_fsiPermissionHardDenied_showStickyHun()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ FSI_FORCE_DEMOTE,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_HARD_DENIED,
+ /* isSticky= */ true);
+ }
+
+ @Test
+ public void testFixNotification_flagForceStickyHun_fsiPermissionSoftDenied_showStickyHun()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ FSI_FORCE_DEMOTE,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_SOFT_DENIED,
+ /* isSticky= */ true);
+ }
+
+ @Test
+ public void testFixNotification_flagForceStickyHun_fsiPermissionGranted_showStickyHun()
+ throws Exception {
+
+ verifyStickyHun(/* flag= */ FSI_FORCE_DEMOTE,
+ /* permissionState= */ PermissionCheckerManager.PERMISSION_GRANTED,
+ /* isSticky= */ true);
+ }
+
@Test
public void fixSystemNotification_withOnGoingFlag_shouldBeNonDismissible()
throws Exception {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index a3977ba..b1a9f08 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -51,6 +51,7 @@
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -169,7 +170,8 @@
mock(ActivityManagerInternal.class),
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
- mock(NotificationChannelLogger.class), new TestableFlagResolver());
+ mock(NotificationChannelLogger.class), new TestableFlagResolver(),
+ mock(PermissionManager.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 7b19e1f..0a80abe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
@@ -43,6 +44,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
@@ -50,6 +52,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -77,6 +80,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
@@ -111,6 +115,8 @@
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
@@ -120,6 +126,8 @@
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.Arrays;
import java.util.HashSet;
@@ -880,6 +888,64 @@
false, false, false, false, false, false, false);
}
+ /**
+ * This test ensures proper logging for BAL_ALLOW_PERMISSION.
+ */
+ @Test
+ public void testBackgroundActivityStartsAllowed_logging() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ MockitoSession mockingSession = mockitoSession()
+ .mockStatic(ActivityTaskManagerService.class)
+ .mockStatic(FrameworkStatsLog.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
+ eq(START_ACTIVITIES_FROM_BACKGROUND),
+ anyInt(), anyInt()));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_notAborted", false,
+ UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
+ UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
+ false, true, false, false, false, false, false);
+ verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+ "", // activity name
+ BackgroundActivityStartController.BAL_ALLOW_PERMISSION,
+ UNIMPORTANT_UID,
+ UNIMPORTANT_UID2));
+ mockingSession.finishMocking();
+ }
+
+ /**
+ * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT.
+ */
+ @Test
+ public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ MockitoSession mockingSession = mockitoSession()
+ .mockStatic(ActivityTaskManagerService.class)
+ .mockStatic(FrameworkStatsLog.class)
+ .mockStatic(PendingIntentRecord.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
+ eq(START_ACTIVITIES_FROM_BACKGROUND),
+ anyInt(), anyInt()));
+ doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when(
+ () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
+ anyObject(), anyInt()));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_notAborted", false,
+ UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
+ Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP,
+ false, true, false, false, false, false, false);
+ verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+ DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME,
+ BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT,
+ UNIMPORTANT_UID,
+ Process.SYSTEM_UID));
+ mockingSession.finishMocking();
+ }
+
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
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 d8037f6..6f633d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -497,6 +497,7 @@
doReturn(insets).when(mainWindow).getInsetsState();
doReturn(attrs).when(mainWindow).getAttrs();
doReturn(true).when(mainWindow).isDrawn();
+ doReturn(true).when(mainWindow).isOnScreen();
doReturn(false).when(mainWindow).isLetterboxedForDisplayCutout();
doReturn(true).when(mainWindow).areAppWindowBoundsLetterboxed();
doReturn(true).when(mLetterboxConfiguration).isLetterboxActivityCornersRounded();
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 3e555a3..c9f758c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -516,7 +516,7 @@
spyOn(mActivity.mLetterboxUiController);
doReturn(true).when(mActivity.mLetterboxUiController)
- .isSurfaceReadyAndVisible(any());
+ .isSurfaceVisible(any());
assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi(
mActivity.findMainWindow()));
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 819b0b2..66711df 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18038,6 +18038,87 @@
public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3;
/**
+ * Callback mode type
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EMERGENCY_CALLBACK_MODE_"}, value = {
+ EMERGENCY_CALLBACK_MODE_CALL,
+ EMERGENCY_CALLBACK_MODE_SMS})
+ public @interface EmergencyCallbackModeType {}
+
+ /**
+ * The callback mode is due to emergency call.
+ * @hide
+ */
+ public static final int EMERGENCY_CALLBACK_MODE_CALL = 1;
+
+ /**
+ * The callback mode is due to emergency SMS.
+ * @hide
+ */
+ public static final int EMERGENCY_CALLBACK_MODE_SMS = 2;
+
+ /**
+ * The reason for changing callback mode.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STOP_REASON_"},
+ value = {
+ STOP_REASON_UNKNOWN,
+ STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED,
+ STOP_REASON_NORMAL_SMS_SENT,
+ STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED,
+ STOP_REASON_EMERGENCY_SMS_SENT,
+ STOP_REASON_TIMER_EXPIRED,
+ STOP_REASON_USER_ACTION,
+ })
+ public @interface EmergencyCallbackModeStopReason {}
+
+ /**
+ * unknown reason.
+ * @hide
+ */
+ public static final int STOP_REASON_UNKNOWN = 0;
+
+ /**
+ * The call back mode is exited due to a new normal call is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED = 1;
+
+ /**
+ * The call back mode is exited due to a new normal SMS is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_NORMAL_SMS_SENT = 2;
+
+ /**
+ * The call back mode is exited due to a new emergency call is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED = 3;
+
+ /**
+ * The call back mode is exited due to a new emergency SMS is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_EMERGENCY_SMS_SENT = 4;
+
+ /**
+ * The call back mode is exited due to timer expiry.
+ * @hide
+ */
+ public static final int STOP_REASON_TIMER_EXPIRED = 5;
+
+ /**
+ * The call back mode is exited due to user action.
+ * @hide
+ */
+ public static final int STOP_REASON_USER_ACTION = 6;
+
+ /**
* Set reception of cell broadcast messages with the list of the given ranges
*
* <p>The ranges set previously will be overridden by the new one. Empty list
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index ead49f0..e0c31ed 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -18,7 +18,6 @@
import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
import android.telephony.satellite.stub.ISatelliteListener;
-import android.telephony.satellite.stub.ISatelliteModemStateConsumer;
import android.telephony.satellite.stub.SatelliteDatagram;
import com.android.internal.telephony.IBooleanConsumer;
@@ -36,6 +35,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -54,6 +54,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -64,15 +65,16 @@
void setSatelliteListeningEnabled(in boolean enable, in IIntegerConsumer errorCallback);
/**
- * Enable or disable the satellite modem. If the satellite modem is enabled, this will also
- * disable the cellular modem, and if the satellite modem is disabled, this will also re-enable
- * the cellular modem.
+ * Request to enable or disable the satellite modem. If the satellite modem is enabled,
+ * this will also disable the cellular modem, and if the satellite modem is disabled,
+ * this will also re-enable the cellular modem.
*
* @param enable True to enable the satellite modem and false to disable.
* @param errorCallback The callback to receive the error code result of the operation.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -80,17 +82,19 @@
* SatelliteError:REQUEST_NOT_SUPPORTED
* SatelliteError:NO_RESOURCES
*/
- void setSatelliteEnabled(in boolean enabled, in IIntegerConsumer errorCallback);
+ void requestSatelliteEnabled(in boolean enabled, in IIntegerConsumer errorCallback);
/**
* Request to get whether the satellite modem is enabled.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether the satellite modem is enabled.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -104,11 +108,13 @@
* Request to get whether the satellite service is supported on the device.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether the satellite service is supported on the device.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -123,11 +129,13 @@
* Request to get the SatelliteCapabilities of the satellite service.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the SatelliteCapabilities of the satellite service.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -147,6 +155,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -164,6 +173,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -177,11 +187,13 @@
* Request to get the maximum number of characters per MO text message on satellite.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the maximum number of characters per MO text message on satellite.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -203,6 +215,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -225,6 +238,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -240,13 +254,14 @@
/**
* Request to get whether this device is provisioned with a satellite provider.
*
- * @param token The token of the device/subscription to be deprovisioned.
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether this device is provisioned with a satellite provider.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -254,7 +269,7 @@
* SatelliteError:REQUEST_NOT_SUPPORTED
* SatelliteError:NO_RESOURCES
*/
- void requestIsSatelliteProvisioned(in String token, in IIntegerConsumer errorCallback,
+ void requestIsSatelliteProvisioned(in IIntegerConsumer errorCallback,
in IBooleanConsumer callback);
/**
@@ -266,6 +281,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -291,6 +307,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -313,11 +330,13 @@
* ISatelliteListener#onSatelliteModemStateChanged.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the current satellite modem state.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -326,17 +345,19 @@
* SatelliteError:NO_RESOURCES
*/
void requestSatelliteModemState(in IIntegerConsumer errorCallback,
- in ISatelliteModemStateConsumer callback);
+ in IIntegerConsumer callback);
/**
* Request to get whether satellite communication is allowed for the current location.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether satellite communication is allowed for the current location.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -353,11 +374,13 @@
* This will return 0 if the satellite is currently visible.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the time after which the satellite will be visible.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
index 4514a71..6a110a9 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
@@ -32,60 +32,60 @@
/**
* Error received from the satellite server.
*/
- SATELLITE_SERVER_ERROR = 2,
+ SERVER_ERROR = 2,
/**
* Error received from the vendor service. This generic error code should be used
* only when the error cannot be mapped to other specific service error codes.
*/
- SATELLITE_SERVICE_ERROR = 3,
+ SERVICE_ERROR = 3,
/**
* Error received from satellite modem. This generic error code should be used only when
* the error cannot be mapped to other specific modem error codes.
*/
- SATELLITE_MODEM_ERROR = 4,
+ MODEM_ERROR = 4,
/**
* Error received from the satellite network. This generic error code should be used only when
* the error cannot be mapped to other specific network error codes.
*/
- SATELLITE_NETWORK_ERROR = 5,
+ NETWORK_ERROR = 5,
/**
* Telephony is not in a valid state to receive requests from clients.
*/
- SATELLITE_INVALID_TELEPHONY_STATE = 6,
+ INVALID_TELEPHONY_STATE = 6,
/**
* Satellite modem is not in a valid state to receive requests from clients.
*/
- SATELLITE_INVALID_MODEM_STATE = 7,
+ INVALID_MODEM_STATE = 7,
/**
* Either vendor service, or modem, or Telephony framework has received a request with
* invalid arguments from its clients.
*/
- SATELLITE_INVALID_ARGUMENTS = 8,
+ INVALID_ARGUMENTS = 8,
/**
* Telephony framework failed to send a request or receive a response from the vendor service
* or satellite modem due to internal error.
*/
- SATELLITE_REQUEST_FAILED = 9,
+ REQUEST_FAILED = 9,
/**
* Radio did not start or is resetting.
*/
- SATELLITE_RADIO_NOT_AVAILABLE = 10,
+ RADIO_NOT_AVAILABLE = 10,
/**
* The request is not supported by either the satellite modem or the network.
*/
- SATELLITE_REQUEST_NOT_SUPPORTED = 11,
+ REQUEST_NOT_SUPPORTED = 11,
/**
* Satellite modem or network has no resources available to handle requests from clients.
*/
- SATELLITE_NO_RESOURCES = 12,
+ NO_RESOURCES = 12,
/**
* Satellite service is not provisioned yet.
*/
- SATELLITE_SERVICE_NOT_PROVISIONED = 13,
+ SERVICE_NOT_PROVISIONED = 13,
/**
* Satellite service provision is already in progress.
*/
- SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14,
+ SERVICE_PROVISION_IN_PROGRESS = 14,
/**
* The ongoing request was aborted by either the satellite modem or the network.
*/
@@ -98,7 +98,7 @@
* Satellite modem timeout to receive ACK or response from the satellite network after
* sending a request to the network.
*/
- SATELLITE_NETWORK_TIMEOUT = 17,
+ NETWORK_TIMEOUT = 17,
/**
* Satellite network is not reachable from the modem.
*/
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index f9c2ea3..4140939 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -130,11 +130,11 @@
}
@Override
- public void setSatelliteEnabled(boolean enable, IIntegerConsumer errorCallback)
+ public void requestSatelliteEnabled(boolean enable, IIntegerConsumer errorCallback)
throws RemoteException {
executeMethodAsync(
- () -> SatelliteImplBase.this.setSatelliteEnabled(enable, errorCallback),
- "setSatelliteEnabled");
+ () -> SatelliteImplBase.this.requestSatelliteEnabled(enable, errorCallback),
+ "requestSatelliteEnabled");
}
@Override
@@ -206,11 +206,11 @@
}
@Override
- public void requestIsSatelliteProvisioned(String token, IIntegerConsumer errorCallback,
+ public void requestIsSatelliteProvisioned(IIntegerConsumer errorCallback,
IBooleanConsumer callback) throws RemoteException {
executeMethodAsync(
() -> SatelliteImplBase.this
- .requestIsSatelliteProvisioned(token, errorCallback, callback),
+ .requestIsSatelliteProvisioned(errorCallback, callback),
"requestIsSatelliteProvisioned");
}
@@ -233,7 +233,7 @@
@Override
public void requestSatelliteModemState(IIntegerConsumer errorCallback,
- ISatelliteModemStateConsumer callback) throws RemoteException {
+ IIntegerConsumer callback) throws RemoteException {
executeMethodAsync(
() -> SatelliteImplBase.this
.requestSatelliteModemState(errorCallback, callback),
@@ -256,7 +256,7 @@
IIntegerConsumer callback) throws RemoteException {
executeMethodAsync(
() -> SatelliteImplBase.this
- .requestTimeForNextSatelliteVisibility(errorCallback, errorCallback),
+ .requestTimeForNextSatelliteVisibility(errorCallback, callback),
"requestTimeForNextSatelliteVisibility");
}
@@ -282,6 +282,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -303,6 +304,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -316,15 +318,16 @@
}
/**
- * Enable or disable the satellite modem. If the satellite modem is enabled, this will also
- * disable the cellular modem, and if the satellite modem is disabled, this will also re-enable
- * the cellular modem.
+ * Request to enable or disable the satellite modem. If the satellite modem is enabled,
+ * this will also disable the cellular modem, and if the satellite modem is disabled,
+ * this will also re-enable the cellular modem.
*
* @param enable True to enable the satellite modem and false to disable.
* @param errorCallback The callback to receive the error code result of the operation.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -332,7 +335,7 @@
* SatelliteError:REQUEST_NOT_SUPPORTED
* SatelliteError:NO_RESOURCES
*/
- public void setSatelliteEnabled(boolean enable, @NonNull IIntegerConsumer errorCallback) {
+ public void requestSatelliteEnabled(boolean enable, @NonNull IIntegerConsumer errorCallback) {
// stub implementation
}
@@ -340,11 +343,13 @@
* Request to get whether the satellite modem is enabled.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether the satellite modem is enabled.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -361,11 +366,13 @@
* Request to get whether the satellite service is supported on the device.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether the satellite service is supported on the device.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -382,11 +389,13 @@
* Request to get the SatelliteCapabilities of the satellite service.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the SatelliteCapabilities of the satellite service.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -408,6 +417,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -427,6 +437,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -442,11 +453,13 @@
* Request to get the maximum number of characters per MO text message on satellite.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the maximum number of characters per MO text message on satellite.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -470,6 +483,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -495,6 +509,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -513,13 +528,14 @@
/**
* Request to get whether this device is provisioned with a satellite provider.
*
- * @param token The token of the device/subscription to be deprovisioned.
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether this device is provisioned with a satellite provider.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -527,8 +543,8 @@
* SatelliteError:REQUEST_NOT_SUPPORTED
* SatelliteError:NO_RESOURCES
*/
- public void requestIsSatelliteProvisioned(@NonNull String token,
- @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+ public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IBooleanConsumer callback) {
// stub implementation
}
@@ -540,6 +556,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -567,6 +584,7 @@
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:NETWORK_ERROR
* SatelliteError:INVALID_MODEM_STATE
@@ -591,11 +609,13 @@
* ISatelliteListener#onSatelliteModemStateChanged.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the current satellite modem state.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -604,7 +624,7 @@
* SatelliteError:NO_RESOURCES
*/
public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback,
- @NonNull ISatelliteModemStateConsumer callback) {
+ @NonNull IIntegerConsumer callback) {
// stub implementation
}
@@ -612,11 +632,13 @@
* Request to get whether satellite communication is allowed for the current location.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* whether satellite communication is allowed for the current location.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
@@ -635,11 +657,13 @@
* This will return 0 if the satellite is currently visible.
*
* @param errorCallback The callback to receive the error code result of the operation.
+ * This must only be sent when the result is not SatelliteError#ERROR_NONE.
* @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive
* the time after which the satellite will be visible.
*
* Valid error codes returned:
* SatelliteError:ERROR_NONE
+ * SatelliteError:SERVICE_ERROR
* SatelliteError:MODEM_ERROR
* SatelliteError:INVALID_MODEM_STATE
* SatelliteError:INVALID_ARGUMENTS
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index 74b42d4..9593c8a 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -340,16 +340,18 @@
* Send command to the implementation of {@link SharedConnectivityService} requesting
* disconnection from the active Tether Network.
*
+ * @param network {@link TetherNetwork} object representing the network the user has requested
+ * to disconnect from.
* @return Returns true if the service received the command. Does not guarantee that the
* disconnection was successful.
*/
- public boolean disconnectTetherNetwork() {
+ public boolean disconnectTetherNetwork(@NonNull TetherNetwork network) {
if (mService == null) {
return false;
}
try {
- mService.disconnectTetherNetwork();
+ mService.disconnectTetherNetwork(network);
} catch (RemoteException e) {
Log.e(TAG, "Exception in disconnectTetherNetwork", e);
return false;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
index 5d79405..52da596 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
@@ -27,7 +27,7 @@
void registerCallback(in ISharedConnectivityCallback callback);
void unregisterCallback(in ISharedConnectivityCallback callback);
void connectTetherNetwork(in TetherNetwork network);
- void disconnectTetherNetwork();
+ void disconnectTetherNetwork(in TetherNetwork network);
void connectKnownNetwork(in KnownNetwork network);
void forgetKnownNetwork(in KnownNetwork network);
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index a0b931f..13084f4 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -117,9 +117,9 @@
}
@Override
- public void disconnectTetherNetwork() {
+ public void disconnectTetherNetwork(TetherNetwork network) {
checkPermissions();
- mHandler.post(() -> onDisconnectTetherNetwork());
+ mHandler.post(() -> onDisconnectTetherNetwork(network));
}
@Override
@@ -323,8 +323,10 @@
* Implementing application should implement this method.
*
* Implementation should initiate a disconnection from the active Tether Network.
+ *
+ * @param network Object identifying the Tether Network the user has requested to disconnect.
*/
- public abstract void onDisconnectTetherNetwork();
+ public abstract void onDisconnectTetherNetwork(@NonNull TetherNetwork network);
/**
* Implementing application should implement this method.
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 815a012..439d456 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -285,25 +285,28 @@
*/
@Test
public void disconnectTetherNetwork_serviceNotConnected_shouldFail() {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
- assertFalse(manager.disconnectTetherNetwork());
+ assertFalse(manager.disconnectTetherNetwork(network));
}
@Test
public void disconnectTetherNetwork() throws RemoteException {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
- manager.disconnectTetherNetwork();
- verify(mService).disconnectTetherNetwork();
+ manager.disconnectTetherNetwork(network);
+ verify(mService).disconnectTetherNetwork(network);
}
@Test
public void disconnectTetherNetwork_remoteException_shouldFail() throws RemoteException {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
- doThrow(new RemoteException()).when(mService).disconnectTetherNetwork();
- assertFalse(manager.disconnectTetherNetwork());
+ doThrow(new RemoteException()).when(mService).disconnectTetherNetwork(any());
+ assertFalse(manager.disconnectTetherNetwork(network));
}
/**
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
index e15be8b..fb8d7bf 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
@@ -56,7 +56,7 @@
public void onConnectTetherNetwork(TetherNetwork network) {}
@Override
- public void onDisconnectTetherNetwork() {}
+ public void onDisconnectTetherNetwork(TetherNetwork network) {}
@Override
public void onConnectKnownNetwork(KnownNetwork network) {}